Android 以太网服务启动流程

Android 以太网服务启动流程

一、引言

  阅读本文需要对Android系统的启动流程有一定的了解。如果读者还没有这方面的知识,建议大家先了解一下这方面的知识,鄙人后面也会专门做相关系列文章。这里先大概简单阐述一下(这里我们重点关注init以上的进程服务),方便阅读本文章。Android 在kernel内核启动后会加载启动Init进程,在Init进程中启动各种服务,包括显示系统的SurfaceFlinger,音频系统AudioFlinger,网络守护进程Netd等等,其中最重要一个进程是system_server进程,其是所有Framework层级系统服务的发动机。Init启动system_server后,会进入system_server的主方法,并且在主方法中调用startOtherService方法启动非关键的一些服务,而我们以太网服务就是从该方法启动。图1-1所示是以太网服务启动的整体流程。下面我们将具体分析各个服务的启动以及相互之间作用关系。
在这里插入图片描述

图1-1 Android以太网服务启动流程

名称解释:

ENF:EthernetNetworkFactory;

ES:EthernetService

ESI:EthernetServiceImpl

CS:ConnectivityService

NMS:NetworkManagementService

NF:NetworkFactory

二 以太网服务的启动流程

2.1 ES的角度分析以太网服务的启动

2.1.1 ES的启动流程

  根据前面的分析及图1-1的流程图,我们知道EthernetService是在SystemServer的startOtherService的方法中启动,下面我们来具体分析一下启动流程。

//framework/base/services/java/com/android/server/SystemServer.java
public final class SystemServer {
    
    
    private static final String ETHERNET_SERVICE_CLASS =  
        "com.android.server.ethernet.EthernetService";
    //Init进程启动System_Server,进入SystemServer的主方法
    public static void main(String[] args) {
    
    
        new SystemServer().run();
    }
    private void run() {
    
    
        startOtherService()
    }
    private void startOtherServices() {
    
    
        //Feature特性,具体定义在Android源码的frameworks/native/data/etc/下
        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||    
          mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
    
    
             traceBeginAndSlog("StartEthernet");
             mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
             traceEnd();
         }
    }
}

这里是通过SystemServiceManager的方式启动ES服务的,这里就不详细介绍。这里在启动ES的时候使用了Feature控制,具体定义在Android源码/frameworks/native/data/etc/下。

<!--frameworks/native/data/etc-->
android.hardware.ethernet.xml
<permissions>
    <feature name="android.hardware.ethernet" />
</permissions>

在设备中的位置是在/vendor/etc/permissions/,该目录保存了大部分厂商的配置的文件:

Mate:/ # ls -l ./vendor/etc/permissions/
total 80
-rw-r--r-- 1 root root  820 2009-01-01 08:00 android.hardware.bluetooth.xml
-rw-r--r-- 1 root root  830 2009-01-01 08:00 android.hardware.bluetooth_le.xml
-rw-r--r-- 1 root root  877 2009-01-01 08:00 android.hardware.camera.front.xml
-rw-r--r-- 1 root root  877 2009-01-01 08:00 android.hardware.camera.xml
-rw-r--r-- 1 root root  834 2009-01-01 08:00 android.hardware.ethernet.xml
-rw-r--r-- 1 root root  870 2009-01-01 08:00 android.hardware.opengles.aep.xml
-rw-r--r-- 1 root root  824 2009-01-01 08:00 android.hardware.sensor.accelerometer.xml
-rw-r--r-- 1 root root 1035 2009-01-01 08:00 android.hardware.touchscreen.multitouch.xml
-rw-r--r-- 1 root root  845 2009-01-01 08:00 android.hardware.usb.accessory.xml
-rw-r--r-- 1 root root  868 2009-01-01 08:00 android.hardware.usb.host.xml
-rw-r--r-- 1 root root  904 2009-01-01 08:00 android.hardware.vulkan.version.xml
-rw-r--r-- 1 root root  843 2009-01-01 08:00 android.hardware.wifi.direct.xml
-rw-r--r-- 1 root root  845 2009-01-01 08:00 android.hardware.wifi.passpoint.xml
-rw-r--r-- 1 root root  829 2009-01-01 08:00 android.hardware.wifi.xml
-rw-r--r-- 1 root root  747 2009-01-01 08:00 android.software.backup.xml
-rw-r--r-- 1 root root  875 2009-01-01 08:00 android.software.ipsec_tunnels.xml
-rw-r--r-- 1 root root  745 2009-01-01 08:00 android.software.midi.xml
-rw-r--r-- 1 root root  753 2009-01-01 08:00 android.software.verified_boot.xml
-rw-r--r-- 1 root root 1093 2009-01-01 08:00 sensor_feature.xml
-rw-r--r-- 1 root root 2555 2009-01-01 08:00 tablet_core_hardware.xml

  设备在系统开机过程中会读取/vendor/etc/permissions/目录下对应的配置文件,然后在SystemServer中启动相关服务的时候会通过该配置文件进行匹配,依此来决定是否启动相关服务,正如我们ES一样。我们平时系统服务裁剪,就可以通过配置Feature的方式决定是否启动对应的服务。

  下面我们具体看下ES的启动流程:

//frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetService.java
public final class EthernetService extends SystemService {
    
                

    private static final String TAG = "EthernetService";
    //这里是以太网服务的真正核心实现
    final EthernetServiceImpl mImpl;
    public EthernetService(Context context) {
    
                             
        super(context); 
        //初始化EthernetServiceImpl服务
        mImpl = new EthernetServiceImpl(context);
    }
                                                                      
    @Override                                                         
    public void onStart() {
    
    
        Log.i(TAG, "Registering service " + Context.ETHERNET_SERVICE);
        publishBinderService(Context.ETHERNET_SERVICE, mImpl);
    }

    @Override                                                         
    public void onBootPhase(int phase) {
    
    
        //在系统SYSTEM_SERVICES_READY阶段,调用EthernetServiceImpl服务的start方法
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
    
    
            mImpl.start();
        }
    }
}                                                                     

  ES服务并不复杂,真正起作用的是ESImpl服务。在EthernetService服务的构造方法中创建了ESI对象。该对象在ES的onStart方法中通过publishBinderService将其注册到SystemManager中以供客户端使用。至此用户就可以通过对外暴露接口来使用以太网的服务了。然后在系统SYSTEM_SERVICES_READY阶段,调用ESI服务的start方法进行初始化的工作。而ESImpl又委托给EthernetTracker来完成以太网的具体工作。

//frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImp.java
public class EthernetServiceImpl extends IEthernetManager.Stub {
    
     
    private static final String TAG = "EthernetServiceImpl";
    private EthernetTracker mTracker;
    
    public void start() {
    
    
       Log.i(TAG, "Starting Ethernet service");
       HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");
       handlerThread.start();
       mHandler = new Handler(handlerThread.getLooper());
       //创建EthernetTracker对象,注意此时的mHandler的looper,后面ENS和CS之间的通信会用的着
       mTracker = new EthernetTracker(mContext, mHandler);
       mTracker.start();            
    }
}

  该构造方法比较简单,主要创建一个EthernetTracker这个对象。该类是以太网络连接的管理对象,Android 以太网框架源码分析启动篇正如中介绍一样,该对象在以太网服务中扮演着重要角色。EthernetTracker可以持有NMS对象mNMService,通过mNMService可以访问到Netd的接口。另外mFactory对象又可以和CS进行相互通信。因此,该对象是整个以太网的中枢所在。

//frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java
final class EthernetTracker {
    
    
    //NMS对象,通过该对象访问Netd的相关接口
    private final INetworkManagementService mNMService;
    private final Handler mHandler;
    //主要更新网络连接状,链路配置,网络能力给ConnectivityService,同时接受来自ConnectivityService
    //禁止自动连接,网络有效性等信息
    private final EthernetNetworkFactory mFactory;
    //存储以太网配置信息,
    private final EthernetConfigStore mConfigStore;
    
    EthernetTracker(Context context, Handler handler) {
    
    
       // The services we use.
       IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
       mNMService = INetworkManagementService.Stub.asInterface(b); 
       mFactory = new EthernetNetworkFactory(handler, context, nc);
       //注册NetworkFactory到CS中,从而创建从CS到ENF(NF)的通道
       mFactory.register();
       mConfigStore = new EthernetConfigStore();
    }
    void start() {
    
    
        try {
    
    
            //注册InterfaceObserver,监听来自底层的状态更新,例如interface的创建与删除等
            mNMService.registerObserver(new InterfaceObserver());
        } catch (RemoteException e) {
    
    
            Log.e(TAG, "Could not register InterfaceObserver " + e);
        }
    }
}

EthernetTracker的构造方法中也不是很复杂,主要完成以下五件事:

  • 获取NMS的Binder引用对象,该对象是和底层Netd通信的主要渠道,底层的一些状态更新,会通过NMS通知到各个系统服务中;
  • 创建ENF这个对象,该对象可以和CS进行相互通信。ENF将网络连接状、链路配置、网络能力等信息传递给CS,而CS会将网路有效性等信息传递给ENF;
  • 调用ENF的register方法在CS中通过AsyncChannel创建单向通道,方便CS向ENF传递网络连接状等信息;同时CS也会通过NetworkAgent来创建从ENF到CS的通道,方便CS想ENF传递网络有效性等信息;这样CS和ENF(NF)之间就建立了双向通道,方便两者之间的相互通信。
  • 创建EthernetConfigStore对象,用于存储以太网的配置信息;
  • 注册来自ENF的Interface的状态信息更新,例如,InterfaceAdd/InterfaceRemove等等。

至此,ES服务就启动完成了, App层如果需要操作以太网,可以通过EthernetManger的Binder调用到ESI中,进而进入中枢枢纽EthernetTracker完成相关操作。下面我们重点看下ENF和CS的之间的双向通道的建立。

2.1.2 NF与CS通道建立流程

  通过上一节我们知道ENF是通过register方法向CS中注册单向通道。这一节我们就从这个方法开始分析。注册目的是为了通信,通常的做法是通过注册到目的端,当目的端状态发生变化是回调相关的方法,从而同步到目的端的状态,这样就可以达到从目的端到源端的调用。

//frameworks/base/core/java/android/net/NetworkFactory.java
public class NetworkFactory extends Handler {
    
    
    private AsyncChannel mAsyncChannel;
    private static final int BASE = Protocol.BASE_NETWORK_FACTORY;
    public static final int CMD_REQUEST_NETWORK = BASE;
    private final SparseArray<NetworkRequestInfo> mNetworkRequests =
        new SparseArray<NetworkRequestInfo>();
    
    public NetworkFactory(Looper looper, Context context, String logTag
        NetworkCapabilities filter) {
    
    
       super(looper);
       mContext = context;
       mCapabilityFilter = filter;
    }                                                                  
    
    public void register() {
    
    
        if (mMessenger == null) {
    
    
           mMessenger = new Messenger(this);
           //注意这里是Messenger不是Messege,最后将其注册到CS中
           mSerialNumber = ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, 
            LOG_TAG);
        }
    }
    @Override
    public void handleMessage(Message msg) {
    
    
       switch (msg.what) {
    
    
          case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    
    
            //在接收到来自CS的CMD_CHANNEL_FULL_CONNECTION消息后创建AsyncChnannel,并且发送
            //CMD_CHANNEL_FULLY_CONNECTED消息给CS,这样就建立双向通道。
            AsyncChannel ac = new AsyncChannel();
            ac.connected(null, this, msg.replyTo);
            ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
                    AsyncChannel.STATUS_SUCCESSFUL);
            mAsyncChannel = ac;
            for (Message m : mPreConnectedQueue) {
    
    
                ac.sendMessage(m);
            }
            break;
          }
          case CMD_REQUEST_NETWORK: {
    
    
             //接收来自CS的CMD_REQUEST_NETWORK消息。
             handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); 
             break;
          }
     }
}

  从NF的名称可以看出,该类是一个网络工厂类,所有注册的网络都会继承该类,例如WiFI/Phone,以及本文中的Ethernet。NF会将自己到CS中。这样每个注册的网络都可以和CS进行通信,方便CS统一管理网络状态。这里需要注意的是此处是Messenger不是Message,这里用到了Android中的AsyncChannel的机制,下面我们可以通过AsyncChannel创建单向和双向的通信通道。AsyncChannel还可以创建跨进程的双向通信,这里就不再详细阐述,感兴趣的读者可以查看相关文章。这里的Messenger对象是一个可以跨进程传递的实例对象,所以是可序列化的,主要为了AsyncChannel可以跨进程通信而设计的类,可以理解为对Handler的封装,而对应的looper是在ESI中创建传递的。

下面我们继续分析registerNetworkFactory方法,代码如下所示:

//framework/base/core/java/android/net/ConnectivityManager.java
public class ConnectivityManager {
    
    
   public static ConnectivityManager from(Context context) {
    
    
      return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
   }
}

//frameworks/base/services/core/java/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub
        implements PendingIntent.OnFinished {
    
    
    final private InternalHandler mHandler;
    
    private static class NetworkFactoryInfo {
    
                                               
       public final String name;//要注册的网络名称,例如Ethernet/wifi等
       public final Messenger messenger;
       public final AsyncChannel asyncChannel;
       public final int factorySerialNumber;
                                                                                    
      NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel, 
            int factorySerialNumber) {
    
                                                  
         this.name = name;                                                           
         this.messenger = messenger;                                                 
         this.asyncChannel = asyncChannel;                                           
         this.factorySerialNumber = factorySerialNumber;                             
      }                                                                               
    }                                                                                   
    //注意此处的Messenger对象是NetworkFactory中传递过来的
    public int registerNetworkFactory(Messenger messenger, String name) {
    
    
        NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
            NetworkFactory.SerialNumber.nextSerialNumber());
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));  
        return nfi.factorySerialNumber;
    }
}

这里NetworkFactoryInfo是CS的一个内部类,主要用户封装一些信息,例如要注册的网络名称,以及要传递的Messenger,以及AysncChannel对象。

  下面通过Handler发送一个EVENT_REGISTER_NETWORK_FACTORY消息,并且携带NetworkFactoryInfo对象。这里的Handler是CS的一个内部类InternelHandler的一个实例对象,其继承自Handler,具有处理消息的能力。下面我们直捣黄龙看下EVENT_REGISTER_NETWORK_FACTORY这个事件的处理。

//ConnectivityService.java
private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos = new HashMap<>();
private class InternalHandler extends Handler {
    
    
   @Override
   public void handleMessage(Message msg) {
    
    
       switch (msg.what) {
    
    
          case EVENT_REGISTER_NETWORK_FACTORY: {
    
    
             handleRegisterNetworkFactory((Messenger)msg.obj);
             break;
          }                                                      
       }
   }
}
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
    
    
    mNetworkFactoryInfos.put(nfi.messenger, nfi);
    nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
}

  这里的mNetworkFactoryInfos是一个HashMap对象,key为前面NetworkFactoryInfo的messenger对象,value为NetworkFactoryInfo。此处将NetworkFactoryInfo添加到mNetworkFactoryInfos中,接着调用NetworkFactoryInfo的实例asynChannel对象的connect方法来创建连接。AsyncChannel其实是Goolge专门为Android开发的通信通道,可以在同进程内传递数据,也可以在不同进程中传递数据。下面我们简单看下起连接过程。

//frameworks/base/core/java/com/android/internal/util/AsyncChannel.java
public class AsyncChannel {
    
    
    public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    
     
       //初始化AsyncChannel中的一些变量,包括mSrcHandler和mSrcMessenger
       connected(srcContext, srcHandler, dstMessenger);
       //先创建单向连接,单向连接成功后,在创建双向连接。
       replyHalfConnected(STATUS_SUCCESSFUL);
    }
    
    public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    
    
      // Initialize source fields
      mSrcContext = srcContext;
      mSrcHandler = srcHandler;
      mSrcMessenger = new Messenger(mSrcHandler);

      // Initialize destination fields
      mDstMessenger = dstMessenger;
    }
    
    private void replyHalfConnected(int status) {
    
    
       Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
       msg.arg1 = status;
       msg.obj = this;
       msg.replyTo = mDstMessenger;
       if (!linkToDeathMonitor()) {
    
    
           // Override status to indicate failure
           msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
       }
       mSrcHandler.sendMessage(msg);                                       
    }
}

通过对上面connect的流程的分析,我们可以得出以下结论:

  • 这里通过connect方法带入参数,初始化AsyncChannel中的变量,其中mSrcHandler是源端Handler,这里应于CS中NetworkStateTrackerHandler的实例对象——mTrackerHandler。主要负责将网路状态等信息通过AsyncChannel发送给源端,达到CS流向ENF(NF)中。最后mDstMessenger真正指向的是ENF的父类NF中的Messenger对象。
  • 最后调用mSrcHandler发送CMD_CHANNEL_HALF_CONNECTED消息指令,此消息会在CS的NetworkStateTrackerHandler中处理,具体逻辑如下:
//ConnectivityService.java
private class NetworkStateTrackerHandler extends Handler {
    
    
     private boolean maybeHandleAsyncChannelMessage(Message msg) {
    
     
         switch (msg.what) {
    
    
            case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
    
     
               handleAsyncChannelHalfConnect(msg);
               break;
            }
            case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
    
    
               NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
               if (nai != null) nai.asyncChannel.disconnect();
               break;
            }
            case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    
    
               handleAsyncChannelDisconnected(msg);
               break;
            }
        }
}

private void handleAsyncChannelHalfConnect(Message msg) {
    
    
    AsyncChannel ac = (AsyncChannel) msg.obj;
    mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage(
        AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
    ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial,
        nri.request);
}

  这里NetworkStateTrackerHandler处理很简单,在接收到CMD_CHANNEL_HALF_CONNECTED消息后,直接调用handleAsyncChannelHalfConnect处理,然后通过AsyncChannel对象ac的mDstMessenger发送CMD_CHANNEL_FULL_CONNECTION消息,创建双向通信通道。最后发送CMD_REQUEST_NETWORK消息创建网络。我们先看CMD_CHANNEL_FULL_CONNECTION消息的处理,此处的mDstMessenger指向的是NF的Messenge中。具体如下:

//NetworkFactory.java 
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    
    
            //在接收到来自CS的CMD_CHANNEL_FULL_CONNECTION消息后创建AsyncChnannel,并且发送
            //CMD_CHANNEL_FULLY_CONNECTED消息给CS,这样就建立双向通道。
            AsyncChannel ac = new AsyncChannel();
            ac.connected(null, this, msg.replyTo);
            ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
                    AsyncChannel.STATUS_SUCCESSFUL);
            mAsyncChannel = ac;
            for (Message m : mPreConnectedQueue) {
    
    
                ac.sendMessage(m);
            }
            break;
          }

NF在接收来自CS的CMD_CHANNEL_FULL_CONNECTION消息后,先创建一个AsyncChannel对象,然后发送CMD_CHANNEL_FULLY_CONNECTED消息。registerNetworkFactory将NF注册到CS的流程就结束了,至此CS可以向NF传递网络连接状态等信息。其实此时已经建立了双向通道,即NF也是可以通过mAsyncChannel对象向CS发送消息的。只不过ENF没有使用mAsyncChannel这个对象,而是使用了一个新的类NetworkAgent,该类内部也有个AsyncChannel的实例对象mAsyncChannel,可以通过对象向CS发送消息。

2.1.3 ENF与CS之间的通信

  在分析ENF与CS的注册流程之前,先看下上一节在NetworkStateTrackerHandler中发送完CMD_CHANNEL_FULL_CONNECTION这个消息后,又发送了CMD_REQUEST_NETWORK消息来Request网络,而处理该消息的地方是在NF的handleMessage方法中:

//NetworkFactory.java
case CMD_REQUEST_NETWORK: {
    
    
     //接收来自CS的CMD_REQUEST_NETWORK消息。
      handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); 
      break;
}

这里处理很简单,直接调用handleAddRequest,这里需要注意的是NetworkRequest类,该类是一个网络请求的封装类,其中包括网络能力,网络请求id以及网络类型等:

public class NetworkRequest implements Parcelable {
    
    
    public final @NonNull NetworkCapabilities networkCapabilities;
    public final int requestId;
    public final Type type;
    
    public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId, Type type) {
    
     
        if (nc == null) {
    
    
           throw new NullPointerException();
        }
        requestId = rId;                                                                
        networkCapabilities = nc;
        this.legacyType = legacyType;
        this.type = type;
    }
   /**
    * @hide                                                                            
    */
   public NetworkRequest(NetworkRequest that) {
    
    
      networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
      requestId = that.requestId;
      this.legacyType = that.legacyType;
      this.type = that.type;
   }
}

我们回到上面,直接看NF中handleAddRequest方法,具体代码如下:

protected void handleAddRequest(NetworkRequest request, int score,              
        int servingFactorySerialNumber) {
    
    
    //创建NetworkRequestInfo对象,并将其保存到mNetworkRequests中
    NetworkRequestInfo n = mNetworkRequests.get(request.requestId);             
    if (n == null) {
    
    
        n = new NetworkRequestInfo(request, score, servingFactorySerialNumber); 
        mNetworkRequests.put(n.request.requestId, n);
    } else {
    
    
        n.score = score;
        n.factorySerialNumber = servingFactorySerialNumber;
    }
    //调用该方法继续请求网络
    evalRequest(n);
}

这里主要完成以下几件事:

  • 创建NetworkRequestInfo对象,该类是NF的一个内部类,主要封装网络请求的一些信息,包括NetworkRequest,网络评分等;
  • 调用evalRequest方法完成网络请求。
//NetFactory.java
private void evalRequest(NetworkRequestInfo n) {
    
    
    //判断是否需要启动该网络
    if (shouldNeedNetworkFor(n)) {
    
    
        //如果满足条件,则使能该网络,否则释放该网络
        needNetworkFor(n.request, n.score);
        n.requested = true;
    } else if (shouldReleaseNetworkFor(n)) {
    
    
        releaseNetworkFor(n.request);
        n.requested = false;
    } else {
    
    
        if (VDBG) log("  done");
    }
}

private boolean shouldNeedNetworkFor(NetworkRequestInfo n) {
    
                                      
                          
    return !n.requested  //如果该网络已经请求,则不作处理 
        //如果该注册网络的score小于NF的mScore,说明该网络优先级最高
        && (n.score < mScore || n.factorySerialNumber == mSerialNumber)                       
        //如果该注册网络不满足网络能了,也不作处理                                                             
        && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter)    
        // 判断该注册网络的底层interface正常                                                                   
        && acceptRequest(n.request, n.score);                                                 
}   
 private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) {
    
                                                                  
     return n.requested //如果网络已经注册过,并且:
         //如果该注册网络得分大于NF的mScore,说明该网络不是最高优先级,所以需要释放该网络;
         //如果该注册注册网络能力不满足网络能力,则释放该网络;
         //如果该注册网络的底层interface异常,则释放该网络
         && ((n.score > mScore && n.factorySerialNumber != mSerialNumber)                 
                 || !n.request.networkCapabilities.satisfiedByNetworkCapabilities(        
                         mCapabilityFilter)
                 || !acceptRequest(n.request, n.score));
 }

这里是整个网络注册系统的关键,其逻辑可以分为两条线:

如果NetworkRequestInfo满足网络使能的条件,则调用needNetworkFor使能该网络,且将NetworkRequestInfo.requested 设置为true。该注册网络使能的条件如下:

  • 该注册的网络之前没有被注册过;
  • 该注册的网络的得分小于NF的得分,即此注册网络优先级高于其他网络的优先级;
  • 该注册的网络的网络能力满足上网的条件;
  • 该注册网络的底层interface正常

如果NetworkRequestInfo满足网络释放的条件,则调用needNetworkFor释放该网络,且将NetworkRequestInfo.requested 设置为false。该注册网络释放的条件如下:

  • 该网络之前注册过,如果没有注册过,则不需要释放;
  • 该网络之前注册过,且其网络得分大于NF的得分,说明此时网络优先级不是最高,则释放网络;
  • 该网络之前注册过,且其网络的网络能力不满足上网条件,则释放该网络;
  • 该网络之前注册过,且其网络的底层interface异常,则释放该网络

  此处ethernet初始化来看,NetworkRequestInfo是新创建的,因此此处requested为false,且此时mScore传入70,而CMD_REQUEST_NETWORK传入的是0, 所以满足网络使能条件,则会调用needNetworkFor方法,而该方法在ENF中实现的。

protected void needNetworkFor(NetworkRequest networkRequest, int score) {
    
               
    NetworkInterfaceState network = networkForRequest(networkRequest);
    if (++network.refCount == 1) {
    
    
        network.start();
    }
}

这里需要注意NetworkInterfaceState这个对象,该类是ENF的内部类,其是ENF向CS传递网络状态,链路配置等信息的核心,其中属性变量NetworkAgent是CS和ENF建立通道的关键。

private static class NetworkInterfaceState {
    
                               
    final String name; //注册网络名称,ethernet/wifi

    private final String mHwAddress;//硬件mac地址
    private final NetworkCapabilities mCapabilities; //网络能力                   
    private final Handler mHandler;
    private final Context mContext;
    private final NetworkInfo mNetworkInfo; //网络状态信息

    private boolean mLinkUp; //链路信息
    private LinkProperties mLinkProperties = new LinkProperties();

    private volatile IIpClient mIpClient;//静态IP相关配置
    private IpClientCallbacksImpl mIpClientCallback;
    private NetworkAgent mNetworkAgent;
    private IpConfiguration mIpConfig;
    
     private void start() {
    
       
         mIpClientCallback = new IpClientCallbacksImpl();
         //创建IpClient的回调
         IpClientUtil.makeIpClient(mContext, name, mIpClientCallback); 
        ....
        new Handler().postDelayed(new Runnable() {
    
     
           @Override
           public void run() {
    
    
             if (mIpClient != null) {
    
    
                 //处理静态Ip相关请求
                 provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);           
              }
            }
        }, 1000);
    }

    private class IpClientCallbacksImpl extends IpClientCallbacks {
    
    
        public void onProvisioningSuccess(LinkProperties newLp) {
    
    
        mHandler.post(() -> onIpLayerStarted(newLp));
    }
}

NetworkInterfaceState的start中注册了IpClientCallbacksImpl的callback,当Ip设置成功后会回调到IpClientCallbacksImpl的onIpLayerStarted方法,并且在改方法中初始化mNetworkAgent变量。

//EthernetNetworkFactory.java
mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext,   
        NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties,
        getNetworkScore(){
    
    });

  至此我们分析到本节的核心NetworkAgent,我们直接看其初始化:

//frameworks/base/core/java/android/net/NetworkAgent.java
public abstract class NetworkAgent extends Handler {
    
    
    private volatile AsyncChannel mAsyncChannel;
    public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, 
        NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc,    
        int factorySerialNumber) {
    
                                                     
       ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
            Context.CONNECTIVITY_SERVICE);
       netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
            new LinkProperties(lp), new NetworkCapabilities(nc), score, misc,
            factorySerialNumber);
    }

}

这里创建CS的Binder引用对象,并且调用registerNetworkAgent方法注册到CS中,在CS的方法中最后调用handleRegisterNetworkAgent方法进行处理,我们直捣黄龙看下这个方法

 private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
    
    
     nai.onNetworkMonitorCreated(networkMonitor);                                               
                                             
     mNetworkAgentInfos.put(nai.messenger, nai);                                                
     synchronized (mNetworkForNetId) {
    
                                                              
         mNetworkForNetId.put(nai.network.netId, nai);                                          
     }
     try {
    
    
         networkMonitor.start();
     } catch (RemoteException e) {
    
    
         e.rethrowAsRuntimeException();
     }
     nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
     NetworkInfo networkInfo = nai.networkInfo;
     nai.networkInfo = null;
     updateNetworkInfo(nai, networkInfo);
     updateUids(nai, null, nai.networkCapabilities);
 }

  这里的NetworkAgentInfo对象和NetworkFactoryInfoy一样,封装了需要ENF传递给CS的信息对象,包括网络状态,链路管理,网络得分等等,最后调用NetworkAgentInfo的connect建立ENF到CS的通信,这个AsyncChannel的connect原理和CS到NF一样,此处就不再分析,CS的接收端是NetworkAgentInfo的Handler中处理。

  至此CS与NF以及ENF与CS之间都建立了双向通道,路已经铺好,就差使用了。

2.2 NMS的启动流程

  NMS的启动ES类似,我们重点关注其构造方法,

public class NetworkManagementService extends INetworkManagementService.Stub {
    
    

   static NetworkManagementService create(Context context, SystemServices services)  
        throws InterruptedException {
    
    
      final NetworkManagementService service =
            new NetworkManagementService(context, services);
       service.connectNativeNetdService();
       return service;
    }
	 private NetworkManagementService(                                              
         Context context, SystemServices services) {
    
    
                                                                               
     mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
     synchronized (mTetheringStatsProviders) {
    
                                      
         mTetheringStatsProviders.put(new NetdTetheringStatsProvider(), "netd");
     }                                                                          
 }
}

其构造方法主要做了以下几件事:

  • 创建NetdUnsolicitedEventListener对象,该对象是作为Listener注册到Netd中,当Netd中有状态变化,比如interface状态的变化,会通过NetdUnsolicitedEventListener回调到NMS中。
  • 通过connectNativeNetdService获取到Netd服务的Binder对象的引用并将其注册到Netd服务中,至此NMS就可以和Netd进行双向通信:NMS可以通过Binder调用Netd中接口 ; Netd状态有变化可以通过NetdUnsolicitedEventListener回调给NMS。

三 小结

  至此,我们以太网服务的启动流程就分析了,其中ENF和CS之间的通双向通信比较复杂,不过理解了AsyncChanel的工作原理后,就不会那么吃力了,尽情启动下一篇应用层使能ethernet功能源码流程分析。今天先打完收工。

猜你喜欢

转载自blog.csdn.net/franc521/article/details/123744684
今日推荐