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;
}