原址: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 onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mStatusView = (TextView)findViewById(R.id.status);
- mAttrsView = (TextView)findViewById(R.id.attrs);
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- bluetoothAdapter.getProfileProxy(this, 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.closeProfileProxy(BluetoothProfile.AVRCP_CONTROLLER, mAvrcpController);
- }
- private BluetoothProfile.ServiceListener mAvrcpServiceListener = new BluetoothProfile.ServiceListener(){
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (profile == BluetoothProfile.AVRCP_CONTROLLER){
- mStatusView.setText("AVRCP_CONTROLLER connected");
- Log.d(TAG, "AvrcpControllerService connected");
- mAvrcpController = (BluetoothAvrcpController) proxy;
- // mAvrcpController.setCallback(new 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 onServiceDisconnected(int profile) {
- if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
- mStatusView.setText("AVRCP_CONTROLLER disconnected");
- Log.d(TAG, "AvrcpControllerService disconnected");
- //mAvrcpController.removeCallback();
- mAvrcpController = null;
- }
- }
- };
- private void sendCommand(int keyCode){
- if (mAvrcpController == null)
- return;
- List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();
- for (BluetoothDevice device : devices){
- Log.d(TAG, "send command to device: "+ keyCode + device.getName() + " " + device.getAddress());
- //该方法是要追踪的重点之二
- mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_PRESS);
- mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_RELEASE);
- }
- }
- public void onPlayButtonClick(View view){
- sendCommand(BluetoothAvrcp.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*/ BluetoothAvrcpController(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() {//aidl
- Intent intent = new Intent(IBluetoothAvrcpController.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 AVRCP Controller Service with " + intent);
- return false;
- }
- return true;
- }
- //这里是应用调用的sendPassThroughCmd方法,该方法调用的是一个service的sendPassThroughCmd方法。
- public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
- if (DBG) Log.d(TAG, "sendPassThroughCmd");
- if (mService != null && isEnabled()) {
- try {
- mService.sendPassThroughCmd(device, keyCode, keyState);
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
- return;
- }
- }
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- }
该类提供了蓝牙AVRCP控制profile。BluetoothAvrcpController是一个通过IPC方式控制AVRCP 服务的代理对象。
[java] view plaincopy
- private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothAvrcpController.Stub.asInterface(service);
上述或得了服务对象。
aidl
[java] view plaincopy
- frameworks/base/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
- interface IBluetoothAvrcpController {
- List<BluetoothDevice> getConnectedDevices();
- List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
- int getConnectionState(in BluetoothDevice device);
- void sendPassThroughCmd(in 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.