原址:http://blog.csdn.net/shichaog/article/details/52182987
由于需要实现avrcp的controller的get attr功能,所以看了下android6的代码调用关系。
app层
这里的app层是指用户编写的应用程序而不是谷歌Android中生成的一些app。如下是调试app的截屏。该app中出现了几个button用于控制targe。
app的代码简短罗列如下:
[java] view plaincopy
- public class MyActivity extends Activity {
- private static final String TAG = "AndroidAvrcpControllerDemo";
- //BluetoothAvrcpController是要追踪的重点之一。
- private BluetoothAvrcpController mAvrcpController;
- private TextView mStatusView;
- private TextView mAttrsView;
- @Override
- public void onCreateBundle savedInstanceState) {
- super.onCreatesavedInstanceState);
- setContentViewR.layout.main);
- mStatusView = TextView)findViewByIdR.id.status);
- mAttrsView = TextView)findViewByIdR.id.attrs);
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter);
- bluetoothAdapter.getProfileProxythis, mAvrcpServiceListener, BluetoothProfile.AVRCP_CONTROLLER);
- mStatusView.setText"Connecting to the AVRCP_CONTROLLER service");
- }
- @Override
- protected void onDestroy) {
- super.onDestroy);
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter);
- //mAvrcpController.removeCallback);
- bluetoothAdapter.closeProfileProxyBluetoothProfile.AVRCP_CONTROLLER, mAvrcpController);
- }
- private BluetoothProfile.ServiceListener mAvrcpServiceListener = new BluetoothProfile.ServiceListener){
- @Override
- public void onServiceConnectedint profile, BluetoothProfile proxy) {
- if profile == BluetoothProfile.AVRCP_CONTROLLER){
- mStatusView.setText"AVRCP_CONTROLLER connected");
- Log.dTAG, "AvrcpControllerService connected");
- mAvrcpController = BluetoothAvrcpController) proxy;
- // mAvrcpController.setCallbacknew AvrcpControllerCallback));
- mStatusView.append"\r\nAvrcp devices: \r\n");
- List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices);
- for BluetoothDevice device : devices)
- mStatusView.append" – " + device.getName) + " " + device.getAddress)+"\r\n");
- }
- }
- @Override
- public void onServiceDisconnectedint profile) {
- if profile == BluetoothProfile.AVRCP_CONTROLLER) {
- mStatusView.setText"AVRCP_CONTROLLER disconnected");
- Log.dTAG, "AvrcpControllerService disconnected");
- //mAvrcpController.removeCallback);
- mAvrcpController = null;
- }
- }
- };
- private void sendCommandint keyCode){
- if mAvrcpController == null)
- return;
- List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices);
- for BluetoothDevice device : devices){
- Log.dTAG, "send command to device: "+ keyCode + device.getName) + " " + device.getAddress));
- //该方法是要追踪的重点之二
- mAvrcpController.sendPassThroughCmddevice, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_PRESS);
- mAvrcpController.sendPassThroughCmddevice, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_RELEASE);
- }
- }
- public void onPlayButtonClickView view){
- sendCommandBluetoothAvrcp.PASSTHROUGH_ID_PLAY);
- }
app里关心两处中卫注释就可以追终到其掉用的frameworks层代码。
frameworks层
[java] view plaincopy
- frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java
- public final class BluetoothAvrcpController implements BluetoothProfile {
- //服务对象
- private IBluetoothAvrcpController mService;
- //创建BluetoothAvrcpController代理对象,用于和本地AVRCP服务交互。
- /*package*/ BluetoothAvrcpControllerContext context, ServiceListener l) {
- mContext = context;
- mServiceListener = l;
- mAdapter = BluetoothAdapter.getDefaultAdapter);
- IBluetoothManager mgr = mAdapter.getBluetoothManager);
- if mgr != null) {
- try {
- mgr.registerStateChangeCallbackmBluetoothStateChangeCallback);
- } catch RemoteException e) {
- Log.eTAG,"",e);
- }
- }
- doBind);
- }
- boolean doBind) {//aidl
- Intent intent = new IntentIBluetoothAvrcpController.class.getName));
- ComponentName comp = intent.resolveSystemServicemContext.getPackageManager), 0);
- intent.setComponentcomp);
- if comp == null || !mContext.bindServiceAsUserintent, mConnection, 0,
- android.os.Process.myUserHandle))) {
- Log.eTAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
- return false;
- }
- return true;
- }
- //这里是应用调用的sendPassThroughCmd方法,该方法调用的是一个service的sendPassThroughCmd方法。
- public void sendPassThroughCmdBluetoothDevice device, int keyCode, int keyState) {
- if DBG) Log.dTAG, "sendPassThroughCmd");
- if mService != null && isEnabled)) {
- try {
- mService.sendPassThroughCmddevice, keyCode, keyState);
- return;
- } catch RemoteException e) {
- Log.eTAG, "Error talking to BT service in sendPassThroughCmd)", e);
- return;
- }
- }
- if mService == null) Log.wTAG, "Proxy not attached to service");
- }
该类提供了蓝牙AVRCP控制profile。BluetoothAvrcpController是一个通过IPC方式控制AVRCP 服务的代理对象。
[java] view plaincopy
- private final ServiceConnection mConnection = new ServiceConnection) {
- public void onServiceConnectedComponentName className, IBinder service) {
- if DBG) Log.dTAG, "Proxy object connected");
- mService = IBluetoothAvrcpController.Stub.asInterfaceservice);
上述或得了服务对象。
aidl
[java] view plaincopy
- frameworks/base/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
- interface IBluetoothAvrcpController {
- List<BluetoothDevice> getConnectedDevices);
- List<BluetoothDevice> getDevicesMatchingConnectionStatesin int[] states);
- int getConnectionStatein BluetoothDevice device);
- void sendPassThroughCmdin BluetoothDevice device, int keyCode, int keyState);
- }
这里描述的是service提供服务的接口函数。
package
[java] view plaincopy
- packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java
- public class AvrcpControllerService extends ProfileService {
- static {
- classInitNative);
- }
- public AvrcpControllerService) {
- mMetadata = new Metadata);
- initNative);
- }
- …
这张图中BluetoothAvrcpControllerBinder了继承了IBluetoothAvrcpController内部内,这是和aidl关联的,这样可以调用aidl的方法接口。如 [java] view plaincopy
- getConnectedDevices
- public List<BluetoothDevice> getConnectedDevices) {
- AvrcpControllerService service = getService);
- if service == null) return new ArrayList<BluetoothDevice>0);
- return service.getConnectedDevices);
- }
该实现最终调用service的getConnectedDevices方法,就是这个文件里的方法。该方法调用native层实现。
上图左侧颜色相同的部分是调用关系
向上层回调关系
类似向下调用关系,直接上图
在升级到android 6之后,这个测试app在高通平台遇到了如下问题:
其提示我ACCESS_BLUETOOTH_AVRCP_CT_DATA权限没有,但是我的Manifest has definitions as follows:
[html] view plaincopy
- <uses-permission android:name="android.permission.BLUETOOTH" />
- <uses-permission android:name="android.permission.ACCESS_BLUETOOTH_AVRCP_CT_DATA" />
I'v tried to remove BLUETOOTH permission to verify that it is surely can get the BLUETOOTH permission. So the question is why I can't get ACCESS_BLUETOOTH_AVRCP_CT_DATA permission.
Since ACCESS_BLUETOOTH_AVRCP_CT_DATA is defined in system Bluetooth.apk. My demo apk should have the same sign as system apks.
The sign is in 签名证书(platform.pk8和platform.x509.pem), which is in directory build/target/product/security. FOTA also use this files.
Android.mk
[html] view plaincopy
- LOCAL_CERTIFICATE := platform
or you may use jarsigner by yourself to sign your apk.