太通透了,Android 流程分析 蓝牙enable流程(应用层/Framework/Service层)

news2024/11/27 12:12:01

 零. 前言

由于Bluedroid的介绍文档有限,以及对Android的一些基本的知识需要了(Android 四大组件/AIDL/Framework/Binder机制/JNI/HIDL等),加上需要掌握的语言包括Java/C/C++等,加上网络上其实没有一个完整的介绍Bluedroid系列的文档,所以不管是蓝牙初学者还是蓝牙从业人员,都有不小的难度,学习曲线也相对较陡,所以我有了这个想法,专门对Bluedroid做一个系统性的介绍,尽可能的涵盖所有内容。

-------------------------------------------------------------------------------------------------------------------------

蓝牙视频教程(跟韦东山老师合作), 其中专题21就是专门针对Bluedroid做的系统介绍

https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22329603896.20.5aeb41f98e267j&id=693788592796

--------------------------------------------------------------------------------------------------------------------------

我们之前介绍过Android的架构,我们本节就介绍下如下图部分:

整个AOSP蓝牙的代码如下:

备注:不同的Android版本下可能路径不同,需要自行去查看下

一. 蓝牙系统服务

这块代码主要在/frameworks/base/services/java/com/android/server/SystemServer.java

在Android系统启动过程中,SystemServer是第一个被启动的进程。当Android设备被开机后,内核会创建一个名为init的进程,init进程会启动Zygote进程,Zygote进程会启动SystemServer进程。因此,SystemServer是整个Android系统启动的核心进程,它负责初始化并启动大部分系统服务和应用程序,是整个Android系统的主要启动入口。

具体来说,SystemServer主要完成以下几个任务:

  • 启动和初始化系统服务:SystemServer会启动和初始化大部分系统服务,例如ActivityManagerService、WindowManagerService、PackageManagerService、PowerManagerService等等。这些服务会在启动过程中被创建并注册到系统服务中心,供其他应用程序和服务调用。
  • 启动和初始化核心应用程序:SystemServer会启动和初始化Android系统中的核心应用程序,例如SystemUI、Settings等等。这些应用程序会在启动过程中被创建并运行,提供各种用户界面和功能。
  • 加载和初始化系统属性:SystemServer会加载和初始化/system/build.prop文件中定义的系统属性,例如设备型号、厂商信息等等。这些属性可以在系统运行时被访问和修改。
  • 启动Adb守护进程:SystemServer会启动Adb守护进程,使得开发者可以通过adb工具来访问设备。

总之,SystemServer是整个Android系统启动过程中的核心进程,负责启动和初始化大部分系统服务和应用程序,为整个系统的运行提供基础支持。SystemServer的启动时间通常在内核启动之后的几秒钟内,具体时间取决于设备的硬件性能和系统配置。

/frameworks/base/services/java/com/android/server/SystemServer.java

SystemServer启动代码通过main函数运行。

/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
    new SystemServer().run();
}

SystemServer().run();执行startOtherServices(t);

/frameworks/base/services/java/com/android/server/SystemServer.java

private void run() {
    ...     

    // Start services.
    try {
        traceBeginAndSlog("StartServices");
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        traceEnd();
    }

    ...

    // Loop forever.
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

然后startOtherServices(t);执行如下代码,开启Bluetooth service类

/frameworks/base/services/java/com/android/server/SystemServer.java

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
	if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
    	Slog.i(TAG, "No Bluetooth Service (factory test)");
    } else if (!context.getPackageManager().hasSystemFeature
            (PackageManager.FEATURE_BLUETOOTH)) {
        Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
    } else {
        t.traceBegin("StartBluetoothService");
        // 启动蓝牙fwk manager service
        mSystemServiceManager.startService(BluetoothService.class);
        t.traceEnd();
    }
    ...
}

/frameworks/base/services/core/java/com/android/server/BluetoothService.java

public BluetoothService(Context context) {
    super(context);
    mBluetoothManagerService = new BluetoothManagerService(context);
}

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

BluetoothManagerService(Context context) {

		Slog.e(TAG, "new BluetoothManagerService");

        // BluetoothManagerService的私有类,主要用于处理一些message
        mHandler = new BluetoothHandler(IoThread.get().getLooper()); 

        mContext = context;

        mWirelessConsentRequired = context.getResources()
                .getBoolean(com.android.internal.R.bool.config_wirelessConsentRequired);

        mCrashes = 0;
        mBluetooth = null;
        mBluetoothBinder = null;
        mBluetoothGatt = null;
        mBinding = false;
        mUnbinding = false;
        mEnable = false;
        mState = BluetoothAdapter.STATE_OFF;
        mQuietEnableExternal = false;
        mEnableExternal = false;
        mAddress = null;
        mName = null;
        mErrorRecoveryRetryCounter = 0;
        mContentResolver = context.getContentResolver();
        // Observe BLE scan only mode settings change.
        registerForBleScanModeChange();
        mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
        mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();

        mIsHearingAidProfileSupported = context.getResources()
                .getBoolean(com.android.internal.R.bool.config_hearing_aid_profile_supported);

        // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
        String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
        if (!TextUtils.isEmpty(value)) {
            boolean isHearingAidEnabled = Boolean.parseBoolean(value);
            Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
            FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
            if (isHearingAidEnabled && !mIsHearingAidProfileSupported) {
                // Overwrite to enable support by FeatureFlag
                mIsHearingAidProfileSupported = true;
            }
        }

        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
        filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
        filter.addAction(Intent.ACTION_SETTING_RESTORED);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiver(mReceiver, filter);

        loadStoredNameAndAddress();
        if (isBluetoothPersistedStateOn()) {
            if (DBG) {
                Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
            }
            mEnableExternal = true;
        }

        String airplaneModeRadios =
                Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
        if (airplaneModeRadios == null || airplaneModeRadios.contains(
                Settings.Global.RADIO_BLUETOOTH)) {
            mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
                    this, IoThread.get().getLooper(), context);
        }

        int systemUiUid = -1;
        // Check if device is configured with no home screen, which implies no SystemUI.
        boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen);
        if (!noHome) {
            PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
            systemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
                    MATCH_SYSTEM_ONLY, USER_SYSTEM);
        }
        if (systemUiUid >= 0) {
            Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid));
        } else {
            // Some platforms, such as wearables do not have a system ui.
            Slog.w(TAG, "Unable to resolve SystemUI's UID.");
        }
        mSystemUiUid = systemUiUid;
    }

到此为止,BluetoothManagerService 就停止在这里等待Binder connection

二. Settings开启蓝牙的流程

其中Apps就是我们所说的Settings app或者你自己写的app

Settings的代码路径如下:packages\apps\Settings

蓝牙的framework 路径如下:frameworks\base\core\java\android\bluetooth

1. 下行方向

我所谓的下行方向就是通过应用层调用到fwk到service到system bt到hidl service到controller这个方向!

framework的函数你可以理解为是API,那么Settings apk或者你自己写的就是调用fwk的api

首先在创建BluetoothEnabler的类中,会获取fwk的BluetoothAdapter class的静态方法getDefaultAdapter获取adapter. 这个api就相当于调用的函数。

/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEnabler.java

public BluetoothEnabler(Context context, SwitchWidgetController switchController,
                        MetricsFeatureProvider metricsFeatureProvider, int metricsEvent,
                        RestrictionUtils restrictionUtils) {
    ...

    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null) {
        // Bluetooth is not supported
        mSwitchController.setEnabled(false);
    }
    ...
}

/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

public static synchronized BluetoothAdapter getDefaultAdapter() {
    if (sAdapter == null) {
        IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
        if (b != null) {
            IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
            sAdapter = new BluetoothAdapter(managerService);
        } else {
            Log.e(TAG, "Bluetooth binder is null");
        }
    }
    return sAdapter;
}

其中IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);

如果蓝牙管理服务(BluetoothManagerService)已经在系统中运行,并且它的服务代理已经被注册到ServiceManager中,那么调用 ServiceManager.getService() 将会直接返回这个已经存在的代理对象,而不会立即触发Binder通信。

后面调用蓝牙enable跟disable方法

/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEnabler.java

private boolean setBluetoothEnabled(boolean isEnabled) {
        return isEnabled ? mBluetoothAdapter.enable() : mBluetoothAdapter.disable();
    }

我们可以看下aidl接口

/system/bt/binder/android/bluetooth/IBluetoothManager.aidl

interface IBluetoothManager
{
    IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
    void unregisterAdapter(in IBluetoothManagerCallback callback);
    void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
    void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
    boolean isEnabled();
    boolean enable(String packageName);
    boolean enableNoAutoConnect(String packageName);
    boolean disable(String packageName, boolean persist);
    int getState();
    IBluetoothGatt getBluetoothGatt();

    boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
    void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);

    String getAddress();
    String getName();

    boolean isBleScanAlwaysAvailable();
    int updateBleAppCount(IBinder b, boolean enable, String packageName);
    boolean isBleAppPresent();
    boolean isHearingAidProfileSupported();
}

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

public boolean enable(String packageName) throws RemoteException {
    ...

    synchronized (mReceiver) {
        mQuietEnableExternal = false;
        mEnableExternal = true;
        // waive WRITE_SECURE_SETTINGS permission check
        sendEnableMsg(false,
                BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
    }
    ...
}

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
    mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));
    addActiveLog(reason, packageName, true);
    mLastEnabledTime = SystemClock.elapsedRealtime();
}

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

public void handleMessage(Message msg) 
{
    switch(msg.what)
    {
        ...
        case MESSAGE_ENABLE:
            handleEnable(mQuietEnable);
        ....
    }
}

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

private void handleEnable(boolean quietMode) {
    mQuietEnable = quietMode;

    try {
        mBluetoothLock.writeLock().lock();
        if ((mBluetooth == null) && (!mBinding)) {
            //Start bind timeout and bind
            Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
            mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
            Intent i = new Intent(IBluetooth.class.getName());
            if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                    UserHandle.CURRENT)) {
                mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
            } else {
                mBinding = true;
            }
        } else if (mBluetooth != null) {
            //Enable bluetooth
            try {
                if (!mQuietEnable) {
                    if (!mBluetooth.enable()) {
                        Slog.e(TAG, "IBluetooth.enable() returned false");
                    }
                } else {
                    if (!mBluetooth.enableNoAutoConnect()) {
                        Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
                    }
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Unable to call enable()", e);
            }
        }
    } finally {
        mBluetoothLock.writeLock().unlock();
    }
}

这个会触发bind,那么被绑定的服务在哪里声明的呢?

/packages/apps/Bluetooth/AndroidManifest.xml

bond后会调用这个函数onServiceConnected

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

private class BluetoothServiceConnection implements ServiceConnection {
    public void onServiceConnected(ComponentName componentName, IBinder service) {
        String name = componentName.getClassName();
        if (DBG) {
            Slog.d(TAG, "BluetoothServiceConnection: " + name);
        }
        Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
        if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
            msg.arg1 = SERVICE_IBLUETOOTH;
        } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
            msg.arg1 = SERVICE_IBLUETOOTHGATT;
        } else {
            Slog.e(TAG, "Unknown service connected: " + name);
            return;
        }
        msg.obj = service;
        mHandler.sendMessage(msg);
    }

}

另外,绑定AdapterService, 这个会触发两个动作:

1)AdapterService静态方法调用

2)AdapterService onCreate方法调用

我们先说第一点哈·,AdapterService静态方法调用

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

static {
    System.loadLibrary("bluetooth_jni");
    classInitNative();
}

System.loadLibrary("bluetooth_jni");

加载bluetooth_jni动态库会触发JNI_OnLoad,这个方法就是把jni的cpp方法注册到java中,这样jave层就可以直接调用jni的cpp代码了,比如后面调用的classInitNative就是jni cpp代码,我们来简单看下一个注册过程

packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

static JNINativeMethod sMethods[] = {
    /* name, signature, funcPtr */
    {"classInitNative", "()V", (void*)classInitNative},
    {"initNative", "(ZZZ)Z", (void*)initNative},
    {"cleanupNative", "()V", (void*)cleanupNative},
    {"enableNative", "()Z", (void*)enableNative},
    {"disableNative", "()Z", (void*)disableNative},
    {"setAdapterPropertyNative", "(I[B)Z", (void*)setAdapterPropertyNative},
    {"getAdapterPropertiesNative", "()Z", (void*)getAdapterPropertiesNative},
    {"getAdapterPropertyNative", "(I)Z", (void*)getAdapterPropertyNative},
    {"getDevicePropertyNative", "([BI)Z", (void*)getDevicePropertyNative},
    {"setDevicePropertyNative", "([BI[B)Z", (void*)setDevicePropertyNative},
    {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
    {"cancelDiscoveryNative", "()Z", (void*)cancelDiscoveryNative},
    {"createBondNative", "([BI)Z", (void*)createBondNative},
    {"createBondOutOfBandNative", "([BILandroid/bluetooth/OobData;)Z",
     (void*)createBondOutOfBandNative},
    {"removeBondNative", "([B)Z", (void*)removeBondNative},
    {"cancelBondNative", "([B)Z", (void*)cancelBondNative},
    {"getConnectionStateNative", "([B)I", (void*)getConnectionStateNative},
    {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative},
    {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative},
    {"getRemoteServicesNative", "([B)Z", (void*)getRemoteServicesNative},
    {"getSocketManagerNative", "()Landroid/os/IBinder;",
     (void*)getSocketManagerNative},
    {"setSystemUiUidNative", "(I)V", (void*)setSystemUiUidNative},
    {"setForegroundUserIdNative", "(I)V", (void*)setForegroundUserIdNative},
    {"alarmFiredNative", "()V", (void*)alarmFiredNative},
    {"readEnergyInfo", "()I", (void*)readEnergyInfo},
    {"dumpNative", "(Ljava/io/FileDescriptor;[Ljava/lang/String;)V",
     (void*)dumpNative},
    {"dumpMetricsNative", "()[B", (void*)dumpMetricsNative},
    {"factoryResetNative", "()Z", (void*)factoryResetNative},
    {"interopDatabaseClearNative", "()V", (void*)interopDatabaseClearNative},
    {"interopDatabaseAddNative", "(I[BI)V", (void*)interopDatabaseAddNative},
    {"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative}};

int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
  return jniRegisterNativeMethods(
      env, "com/android/bluetooth/btservice/AdapterService", sMethods,
      NELEM(sMethods));
}

然后注册好了,下面就可以调用了classInitNative

static void classInitNative(JNIEnv* env, jclass clazz) {
  jclass jniUidTrafficClass = env->FindClass("android/bluetooth/UidTraffic");
  android_bluetooth_UidTraffic.constructor =
      env->GetMethodID(jniUidTrafficClass, "<init>", "(IJJ)V");

  jclass jniCallbackClass =
      env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
  sJniCallbacksField = env->GetFieldID(
      clazz, "mJniCallbacks", "Lcom/android/bluetooth/btservice/JniCallbacks;");

  method_stateChangeCallback =
      env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");

  method_adapterPropertyChangedCallback = env->GetMethodID(
      jniCallbackClass, "adapterPropertyChangedCallback", "([I[[B)V");
  method_discoveryStateChangeCallback = env->GetMethodID(
      jniCallbackClass, "discoveryStateChangeCallback", "(I)V");

  method_devicePropertyChangedCallback = env->GetMethodID(
      jniCallbackClass, "devicePropertyChangedCallback", "([B[I[[B)V");
  method_deviceFoundCallback =
      env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
  method_pinRequestCallback =
      env->GetMethodID(jniCallbackClass, "pinRequestCallback", "([B[BIZ)V");
  method_sspRequestCallback =
      env->GetMethodID(jniCallbackClass, "sspRequestCallback", "([B[BIII)V");

  method_bondStateChangeCallback =
      env->GetMethodID(jniCallbackClass, "bondStateChangeCallback", "(I[BI)V");

  method_aclStateChangeCallback =
      env->GetMethodID(jniCallbackClass, "aclStateChangeCallback", "(I[BI)V");

  method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z");
  method_acquireWakeLock =
      env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z");
  method_releaseWakeLock =
      env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z");
  method_energyInfo = env->GetMethodID(
      clazz, "energyInfoCallback", "(IIJJJJ[Landroid/bluetooth/UidTraffic;)V");

  if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {
    ALOGE("No Bluetooth Library found");
  }
}

这里面主要是获取jave类中的方法,也及时为了jni cpp可以调用jave代码,给回调函数,第二个是加载蓝牙协议栈的库文件,#define DEFAULT_BT_LIBRARY_NAME "libbluetooth.so"

所以第一点就打通了jni cpp代码跟service java上下通信的途径!

然后我们再说第二点AdapterService onCreate方法调用

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

public void onCreate() {
    super.onCreate();
    debugLog("onCreate()");
    ...
    initNative(isGuest(), isNiapMode(), isAtvDevice);
    ...
}

因为前面我们已经jni跟jave的沟通渠道已经导通,所以initNative就是调用jni的函数

/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest,
                       jboolean isNiapMode, jboolean isAtvDevice) {
  ALOGV("%s", __func__);

  ...

  int ret = sBluetoothInterface->init(&sBluetoothCallbacks,
                                      isGuest == JNI_TRUE ? 1 : 0,
                                      isNiapMode == JNI_TRUE ? 1 : 0,
                                      isAtvDevice == JNI_TRUE ? 1 : 0);
  if (ret != BT_STATUS_SUCCESS && ret != BT_STATUS_DONE) {
    ALOGE("Error while setting the callbacks: %d\n", ret);
    sBluetoothInterface = NULL;
    return JNI_FALSE;
  }

...

  return JNI_TRUE;
}

这里就进入到system bt中

另外,当binder通信成功后除了AdapterService静态方法调用以及onCreate方法调用,还有BluetoothManagerService.java中的onServiceConnected调用,这个不能忘记哈· 否则追不下去代码,另外,这些代码分析确实会感觉跳来跳去,还是结合流程图一起看!

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

public void onServiceConnected(ComponentName componentName, IBinder service) {
    String name = componentName.getClassName();
    if (DBG) {
        Slog.d(TAG, "BluetoothServiceConnection: " + name);
    }
    Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
    if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
        msg.arg1 = SERVICE_IBLUETOOTH;
        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
    } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
        msg.arg1 = SERVICE_IBLUETOOTHGATT;
    } else {
        Slog.e(TAG, "Unknown service connected: " + name);
        return;
    }
    msg.obj = service;
    mHandler.sendMessage(msg);
}

会发送MESSAGE_BLUETOOTH_SERVICE_CONNECTED消息出来,我们看下消息处理

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
    if (DBG) {
        Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
    }

    IBinder service = (IBinder) msg.obj;
    try {
        mBluetoothLock.writeLock().lock();
        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
            mBluetoothGatt =
                    IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
            continueFromBleOnState();
            break;
        } // else must be SERVICE_IBLUETOOTH

        mBinding = false;
        mTryBindOnBindTimeout = false;
        mBluetoothBinder = service;
        mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));

        if (!isNameAndAddressSet()) {
            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
            mHandler.sendMessage(getMsg);
            if (mGetNameAddressOnly) {
                return;
            }
        }

		...

        //Do enable request
        try {
            if (!mQuietEnable) {
                if (!mBluetooth.enable()) {
                    Slog.e(TAG, "IBluetooth.enable() returned false");
                }
            } else {
                if (!mBluetooth.enableNoAutoConnect()) {
                    Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
                }
            }
        } catch (RemoteException e) {
            Slog.e(TAG, "Unable to call enable()", e);
        }
    } finally {
        mBluetoothLock.writeLock().unlock();
    }

    ...
    break;
}

获取aidl接口,也就是调用到了这个类下面的enable

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

public synchronized boolean enable(boolean quietMode) {
    // Enforce the user restriction for disallowing Bluetooth if it was set.
    if (mUserManager.hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM)) {
        debugLog("enable() called when Bluetooth was disallowed");
        return false;
    }

    Log.e(TAG, "AdapterService enable");

    debugLog("enable() - Enable called with quiet mode status =  " + quietMode);
    mQuietmode = quietMode;
    mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);
    return true;
}

这个会触发status machine,会调用到OffState中processMessage

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java

public boolean processMessage(Message msg) {
    switch (msg.what) {
        case BLE_TURN_ON:
            transitionTo(mTurningBleOnState);
            break;

        default:
            infoLog("Unhandled message - " + messageString(msg.what));
            return false;
    }
    return true;
}

然后进入到TurningBleOnState类中的enter

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java

public void enter() {
    super.enter();
    sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
    mAdapterService.bringUpBle();
}
void bringUpBle() {
    ...
    //Start Gatt service
    setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON);
}

开启gattservice服务

另外,ProfileService的状态改变会触发AdapterService的onProfileServiceStateChanged

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

public void onProfileServiceStateChanged(ProfileService profile, int state) {
    if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
        throw new IllegalArgumentException(BluetoothAdapter.nameForState(state));
    }
    Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
    m.obj = profile;
    m.arg1 = state;
    mHandler.sendMessage(m);
}

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

private void processProfileServiceStateChanged(ProfileService profile, int state) {
    switch (state) {
        case BluetoothAdapter.STATE_ON:
            if (!mRegisteredProfiles.contains(profile)) {
                Log.e(TAG, profile.getName() + " not registered (STATE_ON).");
                return;
            }
            if (mRunningProfiles.contains(profile)) {
                Log.e(TAG, profile.getName() + " already running.");
                return;
            }
            mRunningProfiles.add(profile);
            if (GattService.class.getSimpleName().equals(profile.getName())) {

                Log.e(TAG, "processProfileServiceStateChanged enableNative");

                // 这个地方就是调用libjni.so的方法,通过jni native调用
                enableNative();
            } else if (mRegisteredProfiles.size() == Config.getSupportedProfiles().length
                    && mRegisteredProfiles.size() == mRunningProfiles.size()) {
                mAdapterProperties.onBluetoothReady();
                updateUuids();
                setBluetoothClassFromConfig();
                initProfileServices();
                getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS);
                getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS_BLE);
                mAdapterStateMachine.sendMessage(AdapterState.BREDR_STARTED);
            }
            break;
        default:
            Log.e(TAG, "Unhandled profile state: " + state);
    }
}

然后这个动作会触发com_android_bluetooth_btservice_adapterService.cpp中的

/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

static jboolean enableNative(JNIEnv* env, jobject obj) {
  ALOGV("%s", __func__);

  if (!sBluetoothInterface) return JNI_FALSE;
  int ret = sBluetoothInterface->enable();
  return (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE
                                                             : JNI_FALSE;
}

其中sBluetoothInterface 是hal接口,定义如下:

typedef struct {
    /** set to sizeof(bt_interface_t) */
    size_t size;
    /**
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
* The |is_atv| flag indicates whether the local device is an Android TV
*/
    int (*init)(bt_callbacks_t* callbacks, bool is_atv);

    /** Enable Bluetooth. */
    int (*enable)(bool guest_mode);

    /** Disable Bluetooth. */
    int (*disable)(void);

    /** Closes the interface. */
    void (*cleanup)(void);

    /** Get all Bluetooth Adapter properties at init */
    int (*get_adapter_properties)(void);

    /** Get Bluetooth Adapter property of 'type' */
    int (*get_adapter_property)(bt_property_type_t type);

    /** Set Bluetooth Adapter property of 'type' */
    /* Based on the type, val shall be one of
* RawAddress or bt_bdname_t or bt_scanmode_t etc
*/
    int (*set_adapter_property)(const bt_property_t *property);

    /** Get all Remote Device properties */
    int (*get_remote_device_properties)(RawAddress *remote_addr);

    /** Get Remote Device property of 'type' */
    int (*get_remote_device_property)(RawAddress *remote_addr,
                                      bt_property_type_t type);

    /** Set Remote Device property of 'type' */
    int (*set_remote_device_property)(RawAddress *remote_addr,
                                      const bt_property_t *property);

    /** Get Remote Device's service record  for the given UUID */
    int (*get_remote_service_record)(const RawAddress& remote_addr,
                                     const bluetooth::Uuid& uuid);

    /** Start SDP to get remote services */
    int (*get_remote_services)(RawAddress *remote_addr);

    /** Start Discovery */
    int (*start_discovery)(void);

    /** Cancel Discovery */
    int (*cancel_discovery)(void);

    /** Create Bluetooth Bonding */
    int (*create_bond)(const RawAddress *bd_addr, int transport);

    /** Create Bluetooth Bond using out of band data */
    int (*create_bond_out_of_band)(const RawAddress *bd_addr, int transport,
                                   const bt_out_of_band_data_t *oob_data);

    /** Remove Bond */
    int (*remove_bond)(const RawAddress *bd_addr);

    /** Cancel Bond */
    int (*cancel_bond)(const RawAddress *bd_addr);

    /**
* Get the connection status for a given remote device.
* return value of 0 means the device is not connected,
* non-zero return status indicates an active connection.
*/
    int (*get_connection_state)(const RawAddress *bd_addr);

    /** BT Legacy PinKey Reply */
    /** If accept==FALSE, then pin_len and pin_code shall be 0x0 */
    int (*pin_reply)(const RawAddress *bd_addr, uint8_t accept,
                     uint8_t pin_len, bt_pin_code_t *pin_code);

    /** BT SSP Reply - Just Works, Numeric Comparison and Passkey
* passkey shall be zero for BT_SSP_VARIANT_PASSKEY_COMPARISON &
* BT_SSP_VARIANT_CONSENT
* For BT_SSP_VARIANT_PASSKEY_ENTRY, if accept==FALSE, then passkey
* shall be zero */
    int (*ssp_reply)(const RawAddress *bd_addr, bt_ssp_variant_t variant,
                     uint8_t accept, uint32_t passkey);

    /** Get Bluetooth profile interface */
    const void* (*get_profile_interface) (const char *profile_id);

    /** Bluetooth Test Mode APIs - Bluetooth must be enabled for these APIs */
    /* Configure DUT Mode - Use this mode to enter/exit DUT mode */
    int (*dut_mode_configure)(uint8_t enable);

    /* Send any test HCI (vendor-specific) command to the controller. Must be in DUT Mode */
    int (*dut_mode_send)(uint16_t opcode, uint8_t *buf, uint8_t len);
    /** BLE Test Mode APIs */
    /* opcode MUST be one of: LE_Receiver_Test, LE_Transmitter_Test, LE_Test_End */
    int (*le_test_mode)(uint16_t opcode, uint8_t *buf, uint8_t len);

    /** Sets the OS call-out functions that bluedroid needs for alarms and wake locks.
* This should be called immediately after a successful |init|.
*/
    int (*set_os_callouts)(bt_os_callouts_t *callouts);

    /** Read Energy info details - return value indicates BT_STATUS_SUCCESS or BT_STATUS_NOT_READY
* Success indicates that the VSC command was sent to controller
*/
    int (*read_energy_info)();

    /**
* Native support for dumpsys function
* Function is synchronous and |fd| is owned by caller.
* |arguments| are arguments which may affect the output, encoded as
* UTF-8 strings.
*/
    void (*dump)(int fd, const char **arguments);

    /**
* Clear /data/misc/bt_config.conf and erase all stored connections
*/
    int (*config_clear)(void);

    /**
* Clear (reset) the dynamic portion of the device interoperability database.
*/
    void (*interop_database_clear)(void);

    /**
* Add a new device interoperability workaround for a remote device whose
* first |len| bytes of the its device address match |addr|.
* NOTE: |feature| has to match an item defined in interop_feature_t (interop.h).
*/
    void (*interop_database_add)(uint16_t feature, const RawAddress *addr, size_t len);
} bt_interface_t;

这个enable是调用libbluetooth.so中的enable,也就是bluedroid bluetooth.cc或者android8之前的bluetooth.c

static int enable() {
    if (!interface_ready()) return BT_STATUS_NOT_READY;

    stack_manager_get_interface()->start_up_stack_async();
    return BT_STATUS_SUCCESS;
}

然后就是走bluedroid流程了

2. 上行方向

上行方向就是hidl service->system bt -> service -> framework -> Settings

协议层上传蓝牙协议栈初始化的callback如下:

/system/bt/btif/src/stack_manager.cc

static void event_signal_stack_up(UNUSED_ATTR void* context) {
  // Notify BTIF connect queue that we've brought up the stack. It's
  // now time to dispatch all the pending profile connect requests.
  btif_queue_connect_next();
  HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);
}

这个就是system bt给bluetooth service jni发送蓝牙初始化成功的callback

/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

static void adapter_state_change_callback(bt_state_t status) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  ALOGV("%s: Status is: %d", __func__, status);

  sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback,
                               (jint)status);
}

因为我们前面已经打通了jni跟adapter service的通信通道,所以直接通过sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback,(jint)status) 就是调用了

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java 中的stateChangeCallback

void stateChangeCallback(int status) {
    if (status == AbstractionLayer.BT_STATE_OFF) {
        debugLog("stateChangeCallback: disableNative() completed");
        mAdapterStateMachine.sendMessage(AdapterState.STACK_DISABLED);
    } else if (status == AbstractionLayer.BT_STATE_ON) {
        String BT_SOC = getSocName();

        if (BT_SOC.equals("pronto")) {
            Log.i(TAG, "setting max audio connection to 2");
            mAdapterProperties.setMaxConnectedAudioDevices(2);
        }
        mAdapterStateMachine.sendMessage(AdapterState.BLE_STARTED);
    } else {
        Log.e(TAG, "Incorrect status " + status + " in stateChangeCallback");
    }
}

然后此部分到AdapterState中处理,由于目前是TurningBleOnState状态,所以入

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java

public boolean processMessage(Message msg) {
    switch (msg.what) {
        case BLE_STARTED:
            transitionTo(mBleOnState);
            break;
    ...
    }

    return true;
}

状态转换,进入mBleOnState状态,所以会触发父类的BaseAdapterState 的enter函数

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java

public void enter() {
    int currState = getStateValue();
    infoLog("entered ");
    mAdapterService.updateAdapterState(mPrevState, currState);
    mPrevState = currState;
}

然后进入AdapterService中处理状态概念

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

void updateAdapterState(int prevState, int newState) {
    mAdapterProperties.setState(newState);
    if (mCallbacks != null) {
        int n = mCallbacks.beginBroadcast();
        debugLog("updateAdapterState() - Broadcasting state " + BluetoothAdapter.nameForState(
                newState) + " to " + n + " receivers.");
        for (int i = 0; i < n; i++) {
            try {
                mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState, newState);
            } catch (RemoteException e) {
                debugLog("updateAdapterState() - Callback #" + i + " failed (" + e + ")");
            }
        }
        mCallbacks.finishBroadcast();
    }

    ...
}

然后进入到framework层来处理

/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

public void onBluetoothStateChange(boolean on) {
        mCallback.onBluetoothStateChange(on);}

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
    Message msg =
            mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState);
    mHandler.sendMessage(msg);
}

frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

case MESSAGE_BLUETOOTH_STATE_CHANGE: {
    int prevState = msg.arg1;
    int newState = msg.arg2;
    if (DBG) {
        Slog.d(TAG,
                "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(
                        prevState) + " > " + BluetoothAdapter.nameForState(
                        newState));
    }
    mState = newState;
    bluetoothStateChangeHandler(prevState, newState);
    
	...
    break;
}

由于gatt服务没有起来,所以进入bluetoothStateChangeHandler需要先进行gatt service的bind

private void bluetoothStateChangeHandler(int prevState, int newState) {
	...

    Intent i = new Intent(IBluetoothGatt.class.getName());
                doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                        UserHandle.CURRENT);
	...
}

这个同样进进入到bind成功,又进入到这个onServiceConnected流程,是不是很熟悉

public void onServiceConnected(ComponentName componentName, IBinder service) {
    String name = componentName.getClassName();
    if (DBG) {
        Slog.d(TAG, "BluetoothServiceConnection: " + name);
    }
    Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
    if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
        msg.arg1 = SERVICE_IBLUETOOTH;
        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
    } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
        msg.arg1 = SERVICE_IBLUETOOTHGATT;
    } else {
        Slog.e(TAG, "Unknown service connected: " + name);
        return;
    }
    msg.obj = service;
    mHandler.sendMessage(msg);
}

发送MESSAGE_BLUETOOTH_SERVICE_CONNECTED消息,然后进入到

frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java,调用continueFromBleOnState

case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
    ...

    IBinder service = (IBinder) msg.obj;
    try {
        mBluetoothLock.writeLock().lock();
        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
            mBluetoothGatt =
                    IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
            continueFromBleOnState();
            break;
        } // else must be SERVICE_IBLUETOOTH

        ...
}

frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

在里面调用mBluetooth.onLeServiceUp();

private void continueFromBleOnState() {
    
	...
	else if (isBluetoothPersistedStateOnBluetooth() ||
		 mEnableExternal) {
		// This triggers transition to STATE_ON
		mBluetooth.updateQuietModeStatus(mQuietEnable);
		mBluetooth.onLeServiceUp();
		persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
	}
	
	...
}

通过aidl接口调用mBluetooth.onLeServiceUp(),然后从service回到了service部分

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

void onLeServiceUp() {
    mAdapterStateMachine.sendMessage(AdapterState.USER_TURN_ON);
}

因为我们前面已经进入了BleOnState状态,所以在这里直接在BleOnState类中处理

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java

public boolean processMessage(Message msg) {
    switch (msg.what) {
        case USER_TURN_ON:
            mAdapterService.startBrEdrStartup();
            transitionTo(mTurningOnState);
            break;

        ...
    }
    return true;
}

进入TurningOnState的状态后,调用enter,然后会调用startProfileServices函数

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java

public void enter() {
    super.enter();
    sendMessageDelayed(BREDR_START_TIMEOUT, BREDR_START_TIMEOUT_DELAY);
    mAdapterService.startProfileServices();
}

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

void startProfileServices() {
    debugLog("startCoreServices()");
    Class[] supportedProfileServices = Config.getSupportedProfiles();
    if (supportedProfileServices.length == 1 && GattService.class.getSimpleName()
            .equals(supportedProfileServices[0].getSimpleName())) {
        mAdapterProperties.onBluetoothReady();
        updateUuids();
        setBluetoothClassFromConfig();
        mAdapterStateMachine.sendMessage(AdapterState.BREDR_STARTED);
    } else {
        setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON);
    }
}

然后又回到packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java处理

public boolean processMessage(Message msg) {
    switch (msg.what) {
        case BREDR_STARTED:
            transitionTo(mOnState);
            break;

        ...
    }
    return true;
}

进入父类的enter处理mAdapterService.updateAdapterState(mPrevState, currState);

所以会触发父类的BaseAdapterState 的enter函数

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java

public void enter() {
    int currState = getStateValue();
    infoLog("entered ");
    mAdapterService.updateAdapterState(mPrevState, currState);
    mPrevState = currState;
}

然后进入AdapterService中处理状态概念

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

void updateAdapterState(int prevState, int newState) {
    mAdapterProperties.setState(newState);
    if (mCallbacks != null) {
        int n = mCallbacks.beginBroadcast();
        debugLog("updateAdapterState() - Broadcasting state " + BluetoothAdapter.nameForState(
                newState) + " to " + n + " receivers.");
        for (int i = 0; i < n; i++) {
            try {
                mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState, newState);
            } catch (RemoteException e) {
                debugLog("updateAdapterState() - Callback #" + i + " failed (" + e + ")");
            }
        }
        mCallbacks.finishBroadcast();
    }

    ...
}

然后进入到framework层来处理

/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

public void onBluetoothStateChange(boolean on) {
        mCallback.onBluetoothStateChange(on);}

/frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
    Message msg =
            mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState);
    mHandler.sendMessage(msg);
}

frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

case MESSAGE_BLUETOOTH_STATE_CHANGE: {
    int prevState = msg.arg1;
    int newState = msg.arg2;
    if (DBG) {
        Slog.d(TAG,
                "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(
                        prevState) + " > " + BluetoothAdapter.nameForState(
                        newState));
    }
    mState = newState;
    bluetoothStateChangeHandler(prevState, newState);
    
	...
    break;
}

然后调用bluetoothStateChangeHandler,这个函数中处理由于前面的服务已经起来,所以我们直接送广播上去

frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java

private void bluetoothStateChangeHandler(int prevState, int newState) {
    ...

    if (isStandardBroadcast) {
        if (prevState == BluetoothAdapter.STATE_BLE_ON) {
            // Show prevState of BLE_ON as OFF to standard users
            prevState = BluetoothAdapter.STATE_OFF;
        }
        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
    }
}

那么广播送上去后,谁来接收呢?当然是Settings apk的BluetoothEnabler类

/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEnabler.java

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Broadcast receiver is always running on the UI thread here,
        // so we don't need consider thread synchronization.
        int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
        handleStateChanged(state);
    }
};

然后就对应的把android的空间蓝牙开关打开了

/packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEnabler.java

void handleStateChanged(int state) {
    switch (state) {
        case BluetoothAdapter.STATE_TURNING_ON:
            mSwitchController.setEnabled(false);
            break;
        case BluetoothAdapter.STATE_ON:
            mSwitchController.setEnabled(true);
            setChecked(true);
            break;
        case BluetoothAdapter.STATE_TURNING_OFF:
            mSwitchController.setEnabled(false);
            break;
        case BluetoothAdapter.STATE_OFF:
            mSwitchController.setEnabled(true);
            setChecked(false);
            break;
        default:
            mSwitchController.setEnabled(true);
            setChecked(false);
    }
}

二. 流程图总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2248397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R语言绘图过程中遇到图例的图块中出现字符“a“的解决方法

R语言绘图过程中遇到图例的图块中出现字符的解决方法 因为我遇到这个问题的时候没在网上找到合适的方法&#xff0c;找到个需要付费的&#xff0c;算了。也许是因为问的方式不同&#xff0c;问了半天AI也回答出来&#xff0c;莫名有些烦躁&#xff0c;打算对代码做个分析&…

【C语言】字符串左旋的三种解题方法详细分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;方法一&#xff1a;逐字符移动法&#x1f4af;方法二&#xff1a;使用辅助空间法&#x1f4af;方法三&#xff1a;三次反转法&#x1f4af;方法对…

【346】Postgres内核 Startup Process 通过 signal 与 postmaster 交互实现 (5)

1. Startup Process 进程 postmaster 初始化过程中, 在进入 ServerLoop() 函数之前,会先通过调用 StartChildProcess() 函数来开启辅助进程,这些进程的目的主要用来完成数据库的 XLOG 相关处理。 如: 核实 pg_wal 和 pg_wal/archive_status 文件是否存在Postgres先前是否发…

大数据面试SQL题-笔记02【查询、连接、聚合函数】

大数据面试SQL题复习思路一网打尽&#xff01;(文档见评论区)_哔哩哔哩_bilibiliHive SQL 大厂必考常用窗口函数及相关面试题 大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】大数据面试SQL题-笔记02【查询、连接、聚合函数】​​​​​​​ 目录 01、查询 01…

【Python中while循环】

一、深拷贝、浅拷贝 1、需求 1&#xff09;拷贝原列表产生一个新列表 2&#xff09;想让两个列表完全独立开&#xff08;针对改操作&#xff0c;读的操作不改变&#xff09; 要满足上述的条件&#xff0c;只能使用深拷贝 2、如何拷贝列表 1&#xff09;直接赋值 # 定义一个…

51单片机从入门到精通:理论与实践指南入门篇(二)

续51单片机从入门到精通&#xff1a;理论与实践指南&#xff08;一&#xff09;https://blog.csdn.net/speaking_me/article/details/144067372 第一篇总体给大家在&#xff08;全局&#xff09;总体上讲解了一下51单片机&#xff0c;那么接下来几天结束详细讲解&#xff0c;从…

【pyspark学习从入门到精通20】机器学习库_3

目录 使用 ML 预测婴儿生存几率 加载数据 创建转换器 创建估计器 创建管道 拟合模型 使用 ML 预测婴儿生存几率 在这一部分&#xff0c;我们将使用前一章中的数据集的一部分来介绍 PySpark ML 的概念。 在这一部分&#xff0c;我们将再次尝试预测婴儿的生存几率。 加载…

【计算机网络】核心部分复习

目录 交换机 v.s. 路由器OSI七层更实用的TCP/IP四层TCPUDP 交换机 v.s. 路由器 交换机-MAC地址 链接设备和设备 路由器- IP地址 链接局域网和局域网 OSI七层 物理层&#xff1a;传输设备。原始电信号比特流。数据链路层&#xff1a;代表是交换机。物理地址寻址&#xff0c;交…

LLamafactory 批量推理与异步 API 调用效率对比实测

背景 在阅读 LLamafactory 的文档时候&#xff0c;发现它支持批量推理: 推理.https://llamafactory.readthedocs.io/zh-cn/latest/getting_started/inference.html 。 于是便想测试一下&#xff0c;它的批量推理速度有多快。本文实现了 下述两种的大模型推理&#xff0c;并对…

【自动化Selenium】Python 网页自动化测试脚本(上)

目录 1、Selenium介绍 2、Selenium环境安装 3、创建浏览器、设置、打开 4、打开网页、关闭网页、浏览器 5、浏览器最大化、最小化 6、浏览器的打开位置、尺寸 7、浏览器截图、网页刷新 8、元素定位 9、元素交互操作 10、元素定位 &#xff08;1&#xff09;ID定位 &…

Table 滚动条始终停靠在可视区域的底部

1. 话题引入 存在这样一个场景&#xff1a;当页面尺寸发生变化时&#xff0c;希望滚动条能够随之动态调整&#xff0c;始终展示在 table 的可视区域的最下方&#xff0c;而不是整个 table 本身的最底部。 这种行为可以提升用户的使用体验&#xff0c;尤其是在处理大数据表格时…

【漏洞复现】CVE-2020-13925

漏洞信息 NVD - CVE-2020-13925 Similar to CVE-2020-1956, Kylin has one more restful API which concatenates the API inputs into OS commands and then executes them on the server; while the reported API misses necessary input validation, which causes the hac…

基于Springboot的心灵治愈交流平台系统的设计与实现

基于Springboot的心灵治愈交流平台系统 介绍 基于Springboot的心灵治愈交流平台系统&#xff0c;后端框架使用Springboot和mybatis&#xff0c;前端框架使用Vuehrml&#xff0c;数据库使用mysql&#xff0c;使用B/S架构实现前台用户系统和后台管理员系统&#xff0c;和不同级别…

快速理解微服务中Gateway的概念

一.基本概念 定义&#xff1a; 在微服务架构中&#xff0c;Spring Cloud Gateway 是一个用于API网关的框架&#xff0c;它是一个基于 Spring Framework 的高效、可扩展的路由器和反向代理&#xff0c;它能够将外部请求转发到适当的微服务&#xff0c;并提供一些与请求处理相关…

Java【多线程】(1)进程与线程

目录 1.前言 2.正文 2.1什么是进程 2.2PCB&#xff08;进程控制块&#xff09; 2.2.1进程id 2.2.2内存指针 2.2.3文件描述符表 2.2.4进程状态 2.2.4.1就绪状态 2.2.4.2阻塞状态 2.2.5进程优先级 2.2.6进程上下文 2.2.7进程的记账信息 2.3CPU操作进程的方法 2.4什…

计算机毕业设计Python+大模型美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

华为鸿蒙内核成为HarmonyOS NEXT流畅安全新基座

HDC2024华为重磅发布全自研操作系统内核—鸿蒙内核&#xff0c;鸿蒙内核替换Linux内核成为HarmonyOS NEXT稳定流畅新基座。鸿蒙内核具备更弹性、更流畅、更安全三大特征&#xff0c;性能超越Linux内核10.7%。 鸿蒙内核更弹性&#xff1a;元OS架构&#xff0c;性能安全双收益 万…

kafka生产者和消费者命令的使用

kafka-console-producer.sh 生产数据 # 发送信息 指定topic即可 kafka-console-producer.sh \ --bootstrap-server bigdata01:9092 \ --topic topicA # 主题# 进程 29124 ConsoleProducer kafka-console-consumer.sh 消费数据 # 消费数据 kafka-console-consumer.sh \ --boo…

构造函数的相关

文章目录 一、构造函数 今天我们要来讲解类的默认成员函数之一的构造函数。 一、构造函数 构造函数是特殊的成员函数&#xff0c;需要注意的是&#xff0c;构造函数虽然名称叫构造&#xff0c;但是构造函数的主要任务并不是开空间创建对象(我们常使用的局部对象是栈帧创建时&…

云服务器部署WebSocket项目

WebSocket是一种在单个TCP连接上进行全双工通信的协议&#xff0c;其设计的目的是在Web浏览器和Web服务器之间进行实时通信&#xff08;实时Web&#xff09; WebSocket协议的优点包括&#xff1a; 1. 更高效的网络利用率&#xff1a;与HTTP相比&#xff0c;WebSocket的握手只…