1,蓝牙协议/服务端的启动

上一篇文章中,分析了Bluetooth.apk启动过程,启动Bluetooth.apk时,一般启动了AdapterService这一对应的服务。查看package/app/Bluetooth的源码,里面主要是一些具体的协议,其中每一个协议对应一个具体的服务。那么,这些服务是何时以及如何启动的呢?

在android 5.1 中,打开蓝牙时,在AdapterService的setProfileServiceState中就会逐个启动支持的服务,方法如下:

private void setProfileServiceState(Class[] services, int state) {
        if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
            debugLog("setProfileServiceState() - Invalid state, leaving...");
            return;
        }

        int expectedCurrentState= BluetoothAdapter.STATE_OFF;
        int pendingState = BluetoothAdapter.STATE_TURNING_ON;
        if (state == BluetoothAdapter.STATE_OFF) {
            expectedCurrentState= BluetoothAdapter.STATE_ON;
            pendingState = BluetoothAdapter.STATE_TURNING_OFF;
        }

        for (int i=0; i <services.length;i++) {
            String serviceName = services[i].getName();
            Integer serviceState = mProfileServicesState.get(serviceName);
            if(serviceState != null && serviceState != expectedCurrentState) {
                debugLog("setProfileServiceState() - Unable to "
                    + (state == BluetoothAdapter.STATE_OFF ? "start" : "stop" )
                    + " service " + serviceName
                    + ". Invalid state: " + serviceState);
                continue;
            }

            debugLog("setProfileServiceState() - "
                + (state == BluetoothAdapter.STATE_OFF ? "Stopping" : "Starting")
                + " service " + serviceName);

           if (state == BluetoothAdapter.STATE_ON && mDisabledProfiles.contains(serviceName)) {
                Log.i(TAG, "skipping " + serviceName + " (disabled)");
                continue;
            }

            if (DBG) {
                Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " +
                        serviceName);
            }

            mProfileServicesState.put(serviceName,pendingState);
            Intent intent = new Intent(this,services[i]);
            intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);
            intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);
            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            startService(intent);
        }
    }

但是在android 6.0 中,在打开蓝牙,最后调用AdapterService的

setGattProfileServiceState的仅仅启动GattService这一服务,紧接着的调用

BluetoothAdapter的enable方法, notifyUserAction方法最后会调用setProfileServiceState方法启动其他的服务,但是这样做好像意义不大。

public boolean enable() {
        android.util.SeempLog.record(56);
        int state = STATE_OFF;
        if (isEnabled() == true){
            if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
            return true;
        }
        //Use service interface to get the exact state
        if (mService != null) {
            try {
               state = mService.getState();
            } catch (RemoteException e) {Log.e(TAG, "", e);}
        }

        if (state == BluetoothAdapter.STATE_BLE_ON) { // 蓝牙已经打开
                Log.e(TAG, "BT is in BLE_ON State");
                notifyUserAction(true); // 发出通知
                return true;
        }
        try {
            return mManagerService.enable();
        } catch (RemoteException e) {Log.e(TAG, "", e);}
        return false;
    }

 在android 6.0中,其他协议的服务启动我有些疑惑,到底在什么时候启动的呢?

请看下节。

2,设置里服务端的启动

在手机里面,这些服务应该都有获取,并且服务端和客户端已经绑定,那么代码在哪儿呢?

在这里android 5.1和android 6.0还是有些微小的区别,代码路径不一样,在android6.0 中,设置里面之外,还有一个文件夹,路径如下,

frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth

包含的文件:


Android连接蓝牙怎么获取蓝牙设备服务的UUID_协议端服务端的获取


基本上每一个profile文件就对应;而在android 5.1 中,这些文件都包含在

packages\apps\Settings\src\com\android\settings\bluetooth之中。其他的基本原理是完全一样的。

启动设置,打开蓝牙设置,设置里的协议客户端就会创建,然后启动服务端并且和服务端绑定在一起,流程图如下:

Android连接蓝牙怎么获取蓝牙设备服务的UUID_客户端_02

这里以PanProfile为例来说明, PanProfile的构造函数如下,

PanProfile(Context context) {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        adapter.getProfileProxy(context, new PanServiceListener(),
                BluetoothProfile.PAN);
    }


private BluetoothPan mService;
 private boolean mIsProfileReady;
private final class PanServiceListener
            implements BluetoothProfile.ServiceListener {

        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            if (V) Log.d(TAG,"Bluetooth service connected");
            mService = (BluetoothPan) proxy;
            mIsProfileReady=true;
        }

        public void onServiceDisconnected(int profile) {
            if (V) Log.d(TAG,"Bluetooth service disconnected");
            mIsProfileReady=false;
        }
    }
private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	private BluetoothHeadsetClient mHfpClient = null;
private void enableHFP() {
	mBluetoothAdapter.getProfileProxy(getApplicationContext(), new ServiceListener() {
			public void onServiceConnected(int profile,BluetoothProfile proxy) {
				if (profile == BluetoothProfile.HEADSET_CLIENT) {
					android.util.Log.d("fang ", "init mBluetoothHeadset");
					mHfpClient = (BluetoothHeadsetClient) proxy;
				}
			}
			public void onServiceDisconnected(int profile) {
				if (profile == BluetoothProfile.HEADSET_CLIENT) {
					mHfpClient = null;
				}
			}
		}, BluetoothProfile.HEADSET_CLIENT);
	}
public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
                                   int profile) {
        if (context == null || listener == null) return false;

        if (profile == BluetoothProfile.HEADSET) {
            BluetoothHeadset headset = new BluetoothHeadset(context, listener);
            return true;
        } else if (profile == BluetoothProfile.A2DP) {
            BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
            return true;
        } else if (profile == BluetoothProfile.A2DP_SINK) {
            BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
            return true;
        } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
            BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
            return true;
        } else if (profile == BluetoothProfile.INPUT_DEVICE) {
            BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
            return true;
        } else if (profile == BluetoothProfile.PAN) {
            BluetoothPan pan = new BluetoothPan(context, listener);
            return true;
        } else if (profile == BluetoothProfile.DUN) {
            BluetoothDun dun = new BluetoothDun(context, listener);
            return true;
        } else if (profile == BluetoothProfile.HEALTH) {
            BluetoothHealth health = new BluetoothHealth(context, listener);
            return true;
        } else if (profile == BluetoothProfile.MAP) {
            BluetoothMap map = new BluetoothMap(context, listener);
            return true;
        } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
            BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
            return true;
        } else if (profile == BluetoothProfile.SAP) {
            BluetoothSap sap = new BluetoothSap(context, listener);
            return true;
        } else if (profile == BluetoothProfile.HID_DEVICE) {
            BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener);
            return true;
        } else {
            return false;
        }
}
BluetoothHeadsetClient(Context context, ServiceListener l) {
        mContext = context;
        mServiceListener = l;
        mAdapter = BluetoothAdapter.getDefaultAdapter();

        IBluetoothManager mgr = mAdapter.getBluetoothManager();
        if (mgr != null) {
            try {
                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
            } catch (RemoteException e) {
                Log.e(TAG,"",e);
            }
        }

        doBind();
    }
boolean doBind() {
        Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
       ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
        intent.setComponent(comp);
        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
                 android.os.Process.myUserHandle())) {
            Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
            return false;
        }
        return true;
    }
<service
            android:process="@string/process"
            android:name = ".hfpclient.HeadsetClientService"
            android:enabled="@bool/profile_supported_hfpclient">
            <intent-filter>
                <action android:name="android.bluetooth.IBluetoothHeadsetClient" />
            </intent-filter>
        </service>
private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            if (DBG) Log.d(TAG, "Proxy object connected");
            mService = IBluetoothHeadsetClient.Stub.asInterface(service);

            if (mServiceListener != null) {
                mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
                        BluetoothHeadsetClient.this);
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName className) {
            if (DBG) Log.d(TAG, "Proxy object disconnected");
            mService = null;
            if (mServiceListener != null) {
                mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT);
            }
        }
};