ConnectivityService属于Android系统服务一员。在systemserver中启动。
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.告诉系统我已经准备就绪。
这里就对实现状态灯使用加深下对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;
}
}
......
......
}