蓝牙之十-avrcp代码调用关系

原址: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 在CODE上查看代码片派生到我的代码片

  1. public class MyActivity extends Activity {  
  2.     private static final String TAG = "AndroidAvrcpControllerDemo";  
  3.   
  4. //BluetoothAvrcpController是要追踪的重点之一。  
  5.     private BluetoothAvrcpController mAvrcpController;  
  6.     private TextView mStatusView;  
  7.     private TextView mAttrsView;  
  8.   
  9.     @Override  
  10.     public void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         setContentView(R.layout.main);  
  13.         mStatusView = (TextView)findViewById(R.id.status);  
  14.         mAttrsView = (TextView)findViewById(R.id.attrs);  
  15.   
  16.         BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  17.         bluetoothAdapter.getProfileProxy(this, mAvrcpServiceListener, BluetoothProfile.AVRCP_CONTROLLER);  
  18.         mStatusView.setText("Connecting to the AVRCP_CONTROLLER service");  
  19.     }  
  20.   
  21.     @Override  
  22.     protected void onDestroy() {  
  23.         super.onDestroy();  
  24.         BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  25.         //mAvrcpController.removeCallback();  
  26.         bluetoothAdapter.closeProfileProxy(BluetoothProfile.AVRCP_CONTROLLER, mAvrcpController);  
  27.     }  
  28.   
  29.     private BluetoothProfile.ServiceListener mAvrcpServiceListener = new BluetoothProfile.ServiceListener(){  
  30.         @Override  
  31.         public void onServiceConnected(int profile, BluetoothProfile proxy) {  
  32.             if (profile == BluetoothProfile.AVRCP_CONTROLLER){  
  33.                 mStatusView.setText("AVRCP_CONTROLLER connected");  
  34.                 Log.d(TAG, "AvrcpControllerService connected");  
  35.   
  36.                 mAvrcpController = (BluetoothAvrcpController) proxy;  
  37. //                mAvrcpController.setCallback(new AvrcpControllerCallback());  
  38.   
  39.                 mStatusView.append("\r\nAvrcp devices: \r\n");  
  40.                 List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();  
  41.                 for (BluetoothDevice device : devices)  
  42.                     mStatusView.append(" – " + device.getName() + " " + device.getAddress()+"\r\n");  
  43.             }  
  44.         }  
  45.   
  46.         @Override  
  47.         public void onServiceDisconnected(int profile) {  
  48.             if (profile == BluetoothProfile.AVRCP_CONTROLLER) {  
  49.                 mStatusView.setText("AVRCP_CONTROLLER disconnected");  
  50.                 Log.d(TAG, "AvrcpControllerService disconnected");  
  51.                 //mAvrcpController.removeCallback();  
  52.                 mAvrcpController = null;  
  53.             }  
  54.         }  
  55.     };  
  56.   
  57.     private void sendCommand(int keyCode){  
  58.         if (mAvrcpController == null)  
  59.             return;  
  60.   
  61.         List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();  
  62.         for (BluetoothDevice device : devices){  
  63.             Log.d(TAG, "send command to device: "+ keyCode + device.getName() + " " + device.getAddress());  
  64.             //该方法是要追踪的重点之二  
  65.             mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_PRESS);  
  66.             mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_RELEASE);  
  67.         }  
  68.     }  
  69.   
  70.     public void onPlayButtonClick(View view){  
  71.         sendCommand(BluetoothAvrcp.PASSTHROUGH_ID_PLAY);  
  72.     }  

app里关心两处中卫注释就可以追终到其掉用的frameworks层代码。

frameworks层

[java] view plaincopy 在CODE上查看代码片派生到我的代码片

  1. frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java  
  2. public final class BluetoothAvrcpController implements BluetoothProfile {  
  3. //服务对象  
  4. private IBluetoothAvrcpController mService;  
  5.    
  6. //创建BluetoothAvrcpController代理对象,用于和本地AVRCP服务交互。  
  7.         /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) {  
  8.         mContext = context;  
  9.         mServiceListener = l;  
  10.         mAdapter = BluetoothAdapter.getDefaultAdapter();  
  11.         IBluetoothManager mgr = mAdapter.getBluetoothManager();  
  12.         if (mgr != null) {  
  13.             try {  
  14.                 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);  
  15.             } catch (RemoteException e) {  
  16.                 Log.e(TAG,"",e);  
  17.             }  
  18.         }  
  19.   
  20.         doBind();  
  21.     }  
  22.   
  23.     boolean doBind() {//aidl  
  24.         Intent intent = new Intent(IBluetoothAvrcpController.class.getName());  
  25.         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);  
  26.         intent.setComponent(comp);  
  27.         if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,  
  28.                 android.os.Process.myUserHandle())) {  
  29.             Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);  
  30.             return false;  
  31.         }  
  32.         return true;  
  33.     }  
  34.   
  35. //这里是应用调用的sendPassThroughCmd方法,该方法调用的是一个service的sendPassThroughCmd方法。  
  36.     public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {  
  37.         if (DBG) Log.d(TAG, "sendPassThroughCmd");  
  38.         if (mService != null && isEnabled()) {  
  39.             try {  
  40.                 mService.sendPassThroughCmd(device, keyCode, keyState);  
  41.                 return;  
  42.             } catch (RemoteException e) {  
  43.                 Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);  
  44.                 return;  
  45.             }  
  46.         }  
  47.         if (mService == null) Log.w(TAG, "Proxy not attached to service");  
  48.     }  

该类提供了蓝牙AVRCP控制profile。BluetoothAvrcpController是一个通过IPC方式控制AVRCP 服务的代理对象。

[java] view plaincopy 在CODE上查看代码片派生到我的代码片

  1. private final ServiceConnection mConnection = new ServiceConnection() {  
  2.     public void onServiceConnected(ComponentName className, IBinder service) {  
  3.         if (DBG) Log.d(TAG, "Proxy object connected");  
  4.         mService = IBluetoothAvrcpController.Stub.asInterface(service);  

上述或得了服务对象。

aidl

[java] view plaincopy 在CODE上查看代码片派生到我的代码片

  1. frameworks/base/core/java/android/bluetooth/IBluetoothAvrcpController.aidl  
  2. interface IBluetoothAvrcpController {  
  3.     List<BluetoothDevice> getConnectedDevices();  
  4.     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);  
  5.     int getConnectionState(in BluetoothDevice device);  
  6.     void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);  
  7. }  

这里描述的是service提供服务的接口函数。

package

[java] view plaincopy 在CODE上查看代码片派生到我的代码片

  1. packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java  
  2.   
  3. public class AvrcpControllerService extends ProfileService {  
  4.   
  5.     static {  
  6.         classInitNative();  
  7.     }  
  8.   
  9.     public AvrcpControllerService() {  
  10.         mMetadata = new Metadata();  
  11.         initNative();  
  12.     }  
  13. …  


这张图中BluetoothAvrcpControllerBinder了继承了IBluetoothAvrcpController内部内,这是和aidl关联的,这样可以调用aidl的方法接口。如 [java] view plaincopy 在CODE上查看代码片派生到我的代码片

  1. getConnectedDevices  
  2.   
  3.   
  4.         public List<BluetoothDevice> getConnectedDevices() {  
  5.             AvrcpControllerService service = getService();  
  6.             if (service == nullreturn new ArrayList<BluetoothDevice>(0);  
  7.             return service.getConnectedDevices();  
  8.         }  

该实现最终调用service的getConnectedDevices方法,就是这个文件里的方法。该方法调用native层实现。

上图左侧颜色相同的部分是调用关系

向上层回调关系

类似向下调用关系,直接上图

在升级到android 6之后,这个测试app在高通平台遇到了如下问题:

其提示我ACCESS_BLUETOOTH_AVRCP_CT_DATA权限没有,但是我的Manifest has definitions as follows:

[html] view plaincopy 在CODE上查看代码片派生到我的代码片

  1. <uses-permission android:name="android.permission.BLUETOOTH" />  
  2. <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 在CODE上查看代码片派生到我的代码片

  1. LOCAL_CERTIFICATE :platform  

or you may use jarsigner by yourself to sign your apk.

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注