ConnectivityService分析

1.概述

ConnectivityService属于Android系统服务一员。在systemserver中启动。

2.分析

1.构造一个ConnectivityService对象,传入之前实例好的所需相关对象(networkManagement,networkStats,networkPolicy),这里不做其他分析
2.将ConnectivityService添加至ServiceManager进行统一管理
3.networkStats和networkPolicy分别绑定ConnectivityService。

                traceBeginAndSlog("StartConnectivityService");
                try {
                    connectivity = new ConnectivityService(
                            context, networkManagement, networkStats, networkPolicy);
                    ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
                    networkStats.bindConnectivityManager(connectivity);
                    networkPolicy.bindConnectivityManager(connectivity);
                } catch (Throwable e) {
                    reportWtf("starting Connectivity Service", e);
                }
                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

这里针对ConnectivityService只做了一些操作,并没有真正的启动,那真正的启动在哪呢?继续往后看,肯定在systemserver中

				final ConnectivityService connectivityF = connectivity;
				......
                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeConnectivityServiceReady");
                try {
                    if (connectivityF != null) connectivityF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Connectivity Service ready", e);
                }
                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

将上面实例好的ConnectivityService对象赋值给final 型的ConnectivityService对象,调用systemReady()。
那么到这里,我们需要关注两个点:
第一:ConnectivityService的构造方法。即上面传参的方法
第二:systemReady()。

接下来一个一个的分析。
frameworks/base/services/core/java/com/android/server/ConnectivityService.java

    public ConnectivityService(Context context, INetworkManagementService netManager,
                               INetworkStatsService statsService, INetworkPolicyManager policyManager) {
        this(context, netManager, statsService, policyManager, new IpConnectivityLog());
    }

可以看到这里的参数分别是INetworkManagementService,INetworkStatsService ,INetworkPolicyManager 三种类型,虽然这里三种都是interface类型定义(aidl),和我们之前看到的构造传参的参数类型略有不同,这里熟悉aidl的朋友就会没什么障碍了,对于不熟悉aidl的朋友可以先知道效果不用懂原理的跟着走,现在只知道刚刚的构造传参的数据都会到这里来了即可(aidl这里不作说明)。
接着看,方法内部调用了this的一个方法,参数五个,这明显就是本类的一个方法,找到这个方法。
方法内部实现有点长,

 @VisibleForTesting
    protected ConnectivityService(Context context, INetworkManagementService netManager,
                                  INetworkStatsService statsService, INetworkPolicyManager policyManager,
                                  IpConnectivityLog logger) {
        if (DBG) log("ConnectivityService starting up");

        mMetricsLog = logger; //初始化IpConnectivityLog 使用IpConnectivityMetrics记录IpConnectvity事件的类
        mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); //创建默认的Internet请求传输
        NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
        mNetworkRequests.put(mDefaultRequest, defaultNRI);
        mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);

        mDefaultMobileDataRequest = createInternetRequestForTransport(
                NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);

        mHandlerThread = createHandlerThread(); //创建一个公共类HandlerThread《ConnectivityServiceThread》。 扩展线程。 用于启动具有looper的新线程的方便类。 然后可以使用looper来创建处理程序类。 请注意,仍然必须调用start()。
        mHandlerThread.start();
        mHandler = new InternalHandler(mHandlerThread.getLooper()); //创建systemReady中需要InternalHandler对象,并获取ConnectivityServiceThread.loop传参
        mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());//创建NetworkStateTrackerHandler ,并获取ConnectivityServiceThread.loop传参

        // setup our unique device name ////设置我们唯一的设备名称
        if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
            String id = Settings.Secure.getString(context.getContentResolver(),
                    Settings.Secure.ANDROID_ID);
            if (id != null && id.length() > 0) {
                String name = new String("android-").concat(id);
                SystemProperties.set("net.hostname", name);
            }
        }

        mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
                Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);

        mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);

		//检查传参是否丢失数据,没有丢失则用本地对象保存起来,丢失则抛出异常
        mContext = checkNotNull(context, "missing Context");
        mNetd = checkNotNull(netManager, "missing INetworkManagementService");
        mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
        mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
        mKeyStore = KeyStore.getInstance();//KeyStore获取单例
        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); //取得电话服务phone

        try {
            mPolicyManager.setConnectivityListener(mPolicyListener); //设置INetworkPolicyManager监听器
            mRestrictBackground = mPolicyManager.getRestrictBackground();
        } catch (RemoteException e) {
            // ouch, no rules updates means some processes may never get network
            loge("unable to register INetworkPolicyListener" + e);
        }

        final PowerManager powerManager = (PowerManager) context.getSystemService(
                Context.POWER_SERVICE); //取得电源服务 power
        mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
        mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_networkTransitionTimeout);
        mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);

        mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE + 1];

        // TODO: What is the "correct" way to do determine if this is a wifi only device?
        boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false);
        log("wifiOnly=" + wifiOnly);
        String[] naStrings = context.getResources().getStringArray(
                com.android.internal.R.array.networkAttributes);
        for (String naString : naStrings) {
            try {
                NetworkConfig n = new NetworkConfig(naString);
                if (VDBG) log("naString=" + naString + " config=" + n);
                if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
                    loge("Error in networkAttributes - ignoring attempt to define type " +
                            n.type);
                    continue;
                }
                if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
                    log("networkAttributes - ignoring mobile as this dev is wifiOnly " +
                            n.type);
                    continue;
                }
                if (mNetConfigs[n.type] != null) {
                    loge("Error in networkAttributes - ignoring attempt to redefine type " +
                            n.type);
                    continue;
                }
                mLegacyTypeTracker.addSupportedType(n.type);

                mNetConfigs[n.type] = n;
                mNetworksDefined++;
            } catch (Exception e) {
                // ignore it - leave the entry null
            }
        }

        // Forcibly add TYPE_VPN as a supported type, if it has not already been added via config.
        //如果尚未通过config添加TYPE_VPN,则强制添加TYPE_VPN作为支持的类型。
        if (mNetConfigs[TYPE_VPN] == null) {
            // mNetConfigs is used only for "restore time", which isn't applicable to VPNs, so we
            // don't need to add TYPE_VPN to mNetConfigs.
            mLegacyTypeTracker.addSupportedType(TYPE_VPN);
            mNetworksDefined++;  // used only in the log() statement below.
        }

        if (VDBG) log("mNetworksDefined=" + mNetworksDefined);

        mProtectedNetworks = new ArrayList();
        int[] protectedNetworks = context.getResources().getIntArray(
                com.android.internal.R.array.config_protectedNetworks);
        for (int p : protectedNetworks) {
            if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
                mProtectedNetworks.add(p);
            } else {
                if (DBG) loge("Ignoring protectedNetwork " + p);
            }
        }

        mTestMode = SystemProperties.get("cm.test.mode").equals("true")
                && SystemProperties.get("ro.build.type").equals("eng");  //mTestMode此处为false  

        mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager); //创建调制解调器

        mPermissionMonitor = new PermissionMonitor(mContext, mNetd); //创建权限监控器mPermissionMonitor 

        //set up the listener for user state for creating user VPNs
        ////为用户状态设置监听器以创建用户VPN
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_STARTED);
        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
        intentFilter.addAction(Intent.ACTION_USER_ADDED);
        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
        mContext.registerReceiverAsUser(
                mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);

        try {
        	//netd注册观察者两个mTethering和mDataActivityObserver
            mNetd.registerObserver(mTethering);
            mNetd.registerObserver(mDataActivityObserver);
        } catch (RemoteException e) {
            loge("Error registering observer :" + e);
        }

        if (DBG) {
            mInetLog = new ArrayList(); //打开DBG 创建ArrayList类型的log list
        }

        mSettingsObserver = new SettingsObserver(mContext, mHandler); //创建内部类SettingsObserver观察者,主要用于观察http代理和移动数据的change
        registerSettingsCallbacks(); //注册SettingsObserver事件回调

        mDataConnectionStats = new DataConnectionStats(mContext);// 创建数据流量连接状态mDataConnectionStats 对象
        mDataConnectionStats.startMonitoring();//开始监听

        mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED); //创建ssh管理连接工具PacManager对象

        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);//取得UserManager服务

		//创建对象KeepaliveTracker
		//管理数据包keepalive请求。 提供停止和启动keepalive请求的方法,并跟踪所有网络中的Keepalive。 该类与ConnectivityService紧密耦合。 它不是线程安全的,只能从ConnectivityService处理程序线程调用其方法。
        mKeepaliveTracker = new KeepaliveTracker(mHandler);
        mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager, 
                mContext.getSystemService(NotificationManager.class)); //实例NetworkNotificationManager对象

        final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
                LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT);
        final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(),
                Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
                LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
        mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);  //创建LingerMonitor对象 *监视默认网络延迟事件并可能通知用户网络转换的类。

		//用于封装“智能网络”管理的类,用于在例如上游连接丢失或某些关键链路故障发生时避免不良Wi-Fi。
  这使设备可以切换到另一种形式的连接,例如
  移动,如果它可用和工作。 如果给出了Runnable | cb |,则在提供的Handler线程上调用Runnable | cb |是否计算出的“avoid bad wifi”值会发生变化。
  禁用此功能可以通过禁用不同的代码路径将设备恢复到大约2012-13版的网络复杂程度,每个代码路径都有助于维持连续,有效的Internet连接。
        mAvoidBadWifiTracker = createAvoidBadWifiTracker(
                mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
        mAvoidBadWifiTracker.start();
    }

该内部构造方法里面干了些什么,我们先不做详解,这里涉及了许多的类,我们就单针对这个构造方法进行下简单的分析。
ps:部分已经在上面的注释中了。
看完注释,其实对笔者来说,最有用的一个就是NetworkStateTrackerHandler这个handler处理。基本上这里处理的消息也就贯穿了整个Connectivity事件,笔者也是因为需要在平台中添加两个网络状态灯,这才进行了一些分析。具体实现见part3.
至此,虽然这个构造里面涉及东西比较多,但是经过上面的分析,ConnectivityService构造里大概干了什么也差不多清楚了。回想下刚刚systemserver中,对于ConnectivityService我们是不是突然忘记了什么,刚刚有提到的,对,就是systemReady()。我们先把systemserver中的疑虑解决掉,然后再去ConnectivityService内部看看具体的世界。
说到这,systemReady这个方法好像是Android源码里的一个习惯甚至说是标准写法,每个服务好像都有这么一个方法。看看里面干了什么

 void systemReady() {
        loadGlobalProxy();  //加载全局代理,这里的全局代理具体指什么,目前不太清楚,猜猜应该就是像wifi这种连接代理?

        synchronized (this) {
            mSystemReady = true;
            if (mInitialBroadcast != null) {
                mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL); //线程同步,mSystemReady 置为真,表示ConnectivityService.systemReady已经启动
                mInitialBroadcast = null;
            }
        }
        // load the global proxy at startup //在启动时加载全局代理
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY)); 

        // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
        // for user to unlock device too.
        ////尝试启动跟踪器,但KeyStore尚未为二级用户做好准备,因此请等待用户解锁设备。
        updateLockdownVpn();

        // Configure whether mobile data is always on. ////配置移动数据是否始终开启。
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));

        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));

        mPermissionMonitor.startMonitoring(); //权限监控器开始监听,这里需要些什么权限?也不是太清楚
    }

代码很短,一些注释已经写在上面,另外我们可以看到这个systemReady中有个mHandler的对象,这个一看就会知道是处理消息的,但具体是干什么的,继续跟踪看看

    /**
     * Handler used for internal events.
     */
    final private InternalHandler mHandler;

这里注释到时网络相关的handler处理。先不往深入跟踪。暂时就此打住。
我们先看看上面systemReady中mHandler发出的几条消息干嘛的

     * used internally to reload global proxy settings
     * 内部用于重新加载全局代理设置
     */
    private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
    /**
     * used internally to (re)configure mobile data always-on settings.
     * 内部使用(重新)配置移动数据永远在线设置。
     */
    private static final int EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON = 30;
        /**
     * Used internally to indicate the system is ready.
     * 内部使用以指示系统已准备就绪。
     */
    private static final int EVENT_SYSTEM_READY = 25;

看到这里就知道systemReady应该是干了这么几件事:
1.加载全局代理
2.发送粘性广播
3.发送重新加载全局代理设置
4.发送(重新)配置移动数据永远在线设置
5.告诉系统我已经准备就绪。

3.使用及实现

这里就对实现状态灯使用加深下对ConnectivityService的理解。
1.添加相关包的引用

import com.android.server.LocalServices;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;

2.我们看到在网络状态发生变化的时候,NetworkStateTrackerHandler会收到NetworkAgent.EVENT_NETWORK_INFO_CHANGED这个事件。
进而对这个事件的处理是updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo)
那么,要实现我所需要的功能,在这里面动手即可

        Light mWifiLed = null;
        Light mThreeFourG = null;
        
        LightsManager lights = LocalServices.getService(LightsManager.class);
        mThreeFourG = lights.getLight(LightsManager.LIGHT_ID_THREEFOURG);
        mWifiLed = lights.getLight(LightsManager.LIGHT_ID_WIFI);

这里对我们需要操作的灯,进行了获取,初始化等操作,接下来找到相关状态改变的地方添加控制逻辑即可。
在这个方法中可以看到系统对网络状态的判断作了分类处理,我们跟着添加控制逻辑即可。

private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
		......
		......
		if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
			......
			......
			switch (newInfo.getType()) {
	                case ConnectivityManager.TYPE_WIFI:
	                    mWifiLed.setBrightness(1);
	                    break;
	                case ConnectivityManager.TYPE_MOBILE:
	                    mThreeFourG.setBrightness(1);
	                    break;
	                default:
	                    loge("connected unkown network type is" + newInfo.getType());
	                    break;
	       }
		} else if (state == NetworkInfo.State.DISCONNECTED) {
			......
			......
			switch (newInfo.getType()) {
                case ConnectivityManager.TYPE_WIFI:
                    mWifiLed.setBrightness(0);
                    break;
                case ConnectivityManager.TYPE_MOBILE:
                    mThreeFourG.setBrightness(0);
                    break;
                default:
                    loge("disconnect unkown network type is" + newInfo.getType());
                    break;
            }
		}
		......
		......
}

你可能感兴趣的:(android)