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

由于需要实现avrcp的controller的get attr功能,所以看了下android6的代码调用关系。

蓝牙之十-avrcp代码调用关系_第1张图片

app层

这里的app层是指用户编写的应用程序而不是谷歌android中生成的一些app。如下是调试app的截屏。该app中出现了几个button用于控制targe。

蓝牙之十-avrcp代码调用关系_第2张图片

app的代码简短罗列如下:

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 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 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层

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 服务的代理对象。

    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

frameworks/base/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
interface IBluetoothAvrcpController {
    List getConnectedDevices();
    List getDevicesMatchingConnectionStates(in int[] states);
    int getConnectionState(in BluetoothDevice device);
    void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
}
这里描述的是service提供服务的接口函数。

package

packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java

public class AvrcpControllerService extends ProfileService {

    static {
        classInitNative();
    }

    public AvrcpControllerService() {
        mMetadata = new Metadata();
        initNative();
    }
...

蓝牙之十-avrcp代码调用关系_第3张图片
这张图中BluetoothAvrcpControllerBinder了继承了IBluetoothAvrcpController内部内,这是和aidl关联的,这样可以调用aidl的方法接口。如
getConnectedDevices


        public List getConnectedDevices() {
            AvrcpControllerService service = getService();
            if (service == null) return new ArrayList(0);
            return service.getConnectedDevices();
        }

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

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


向上层回调关系

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

蓝牙之十-avrcp代码调用关系_第4张图片


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

蓝牙之十-avrcp代码调用关系_第5张图片

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

	
	
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

LOCAL_CERTIFICATE := platform

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

你可能感兴趣的:(蓝牙)