Android9.0 网络框架之--Tethering 热点
一、概述:最近Android P 平台遇到一个打开车机热点,手机连接后不能上网的 问题,下面是正常的log和异常的log
热点正常能上网的log:
热点异常不能上网的log:
通过log发现Tethering: Found upstream interface(s): null 所以出现不能上网的情况,这里也分析一下打开热点,连接上网的过程。
参考博客:
https://blog.csdn.net/weixin_42093428/article/details/84062557
二、打开热点的流程
调用ConnectivityManager 的 startTethering方法
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
Preconditions.checkNotNull(callback, “OnStartTetheringCallback cannot be null.”);
ResultReceiver wrappedCallback = new ResultReceiver(handler) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == TETHER_ERROR_NO_ERROR) {
callback.onTetheringStarted();
} else {
callback.onTetheringFailed();
}
}
};
try {
String pkgName = mContext.getOpPackageName();
Log.i(TAG, "startTethering caller:" + pkgName);
mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
} catch (RemoteException e) {
Log.e(TAG, "Exception trying to start tethering.", e);
wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
}
}
这里 mService.startTethering,mService 实际上就是ConnectivityService ,我们看看ConnectivityService 的startTethering 方法
@Override
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (!isTetheringSupported()) {
receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
return;
}
mTethering.startTethering(type, receiver, showProvisioningUi);
}
如果系统支持热点功能,就会调用Tethering 的 startTethering 方法
代码路径:frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
if (!isTetherProvisioningRequired()) {
enableTetheringInternal(type, true, receiver);
return;
}
if (showProvisioningUi) {
runUiTetherProvisioningAndEnable(type, receiver);
} else {
runSilentTetherProvisioningAndEnable(type, receiver);
}
}
这里传入的showProvisioningUi 为false ,接着走 runSilentTetherProvisioningAndEnable(type, receiver);
private void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
sendSilentTetherProvisionIntent(type, proxyReceiver);
}
private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
Intent intent = new Intent();
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
intent.putExtra(EXTRA_RUN_PROVISION, true);
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
intent.setComponent(TETHER_SERVICE);
final long ident = Binder.clearCallingIdentity();
try {
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
这里面会启动一个TETHER_SERVICE,他的包名类名是com.android.settings/.wifi.tether.TetherService ,原来走了一圈最后还是走到了Settings 的代码中了。
TetherService 中最后会发送一个广播
private void startProvisioning(int index) {
if (index < mCurrentTethers.size()) {
Intent intent = getProvisionBroadcastIntent(index);
setEntitlementAppActive(index);
if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction()
+ " type: " + mCurrentTethers.get(index));
sendBroadcast(intent);
mInProvisionCheck = true;
}
}
private Intent getProvisionBroadcastIntent(int index) {
String provisionAction = getResources().getString(
com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui);
Intent intent = new Intent(provisionAction);
int type = mCurrentTethers.get(index);
intent.putExtra(TETHER_CHOICE, type);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
return intent;
}