一、引言
阅读本文需要对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/,该目录保存了大部分厂商的配置的文件:
DTEN:/ # 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