接上篇。
上篇最后有提到连接connect,这里接着向下看。
private void connect(int numShares) {
if (D) {
Log.d(TAG, "Create ClientSession with transport " + mTransport1.toString());
}
try {
mCs = new ClientSession(mTransport1);
mConnected = true;
} catch (IOException e1) {
Log.e(TAG, "OBEX session create error");
}
if (mConnected) {
mConnected = false;
HeaderSet hs = new HeaderSet();
hs.setHeader(HeaderSet.COUNT, (long) numShares);
synchronized (this) {
mWaitingForRemote = true;
}
try {
mCs.connect(hs);
if (D) {
Log.d(TAG, "OBEX session created");
}
mConnected = true;
} catch (IOException e) {
Log.e(TAG, "OBEX session connect error");
}
}
synchronized (this) {
mWaitingForRemote = false;
}
}
public HeaderSet connect(final HeaderSet header) throws IOException {
...
/*
* Write the OBEX CONNECT packet to the server.
* Byte 0: 0x80
* Byte 1&2: Connect Packet Length
* Byte 3: OBEX Version Number (Presently, 0x10)
* Byte 4: Flags (For TCP 0x00)
* Byte 5&6: Max OBEX Packet Length (Defined in MAX_PACKET_SIZE)
* Byte 7 to n: headers
*/
byte[] requestPacket = new byte[totalLength];
int maxRxPacketSize = ObexHelper.getMaxRxPacketSize(mTransport);
// We just need to start at byte 3 since the sendRequest() method will
// handle the length and 0x80.
requestPacket[0] = (byte)0x10;
requestPacket[1] = (byte)0x00;
requestPacket[2] = (byte)(maxRxPacketSize >> 8);
requestPacket[3] = (byte)(maxRxPacketSize & 0xFF);
if (head != null) {
System.arraycopy(head, 0, requestPacket, 4, head.length);
}
// Since we are not yet connected, the peer max packet size is unknown,
// hence we are only guaranteed the server will use the first 7 bytes.
if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
throw new IOException("Packet size exceeds max packet size for connect");
}
HeaderSet returnHeaderSet = new HeaderSet();
sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null, false);
/*
* Read the response from the OBEX server.
* Byte 0: Response Code (If successful then OBEX_HTTP_OK)
* Byte 1&2: Packet Length
* Byte 3: OBEX Version Number
* Byte 4: Flags3
* Byte 5&6: Max OBEX packet Length
* Byte 7 to n: Optional HeaderSet
*/
if (returnHeaderSet.responseCode == ResponseCodes.OBEX_HTTP_OK) {
mObexConnected = true;
}
setRequestInactive();
return returnHeaderSet;
}
这里的注释很清楚:
其中requestPacket为Obex cmd的Byte 3后面的数据,前两个Byte在sendRequest中添加。
ObexHelper.OBEX_OPCODE_CONNECT = 0x80
public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
PrivateInputStream privateInput, boolean srmActive) throws IOException {
...
int bytesReceived;
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write((byte)opCode);
// Determine if there are any headers to send
if (head == null) {
out.write(0x00);
out.write(0x03);
} else {
out.write((byte)((head.length + 3) >> 8));
out.write((byte)(head.length + 3));
out.write(head);
}
if (!skipSend) {
// Write the request to the output stream and flush the stream
mOutput.write(out.toByteArray());
// TODO: is this really needed? if this flush is implemented
// correctly, we will get a gap between each obex packet.
// which is kind of the idea behind SRM to avoid.
// Consider offloading to another thread (async action)
mOutput.flush();
}
...
}
这里将0x80和length写进前两位,再通过mOutput写入。
在ClientSession构造函数中mOutput = trans.openOutputStream()
public ClientSession(final ObexTransport trans) throws IOException {
mInput = trans.openInputStream();
mOutput = trans.openOutputStream();
mOpen = true;
mRequestActive = false;
mLocalSrmSupported = trans.isSrmSupported();
mTransport = trans;
}
trans是上篇中提到的 transport = new BluetoothObexTransport(mBtSocket);
public OutputStream openOutputStream() throws IOException {
return mSocket.getOutputStream();
}
mSocket就是之前BluetoothOppTransfer中的mBtSocket = mDevice.createInsecureL2capSocket(mL2cChannel);
BluetoothSocket.java
public OutputStream getOutputStream() throws IOException {
return mOutputStream;
}
所以mOutput就是BluetoothSocket中的mOutputStream
BluetoothOutputStream.java
public void write(byte[] b, int offset, int count) throws IOException {
if (b == null) {
throw new NullPointerException("buffer is null");
}
if ((offset | count) < 0 || count > b.length - offset) {
throw new IndexOutOfBoundsException("invalid offset or length");
}
mSocket.write(b, offset, count);
}
BluetoothSocket.java
/*package*/ int write(byte[] b, int offset, int length) throws IOException {
//TODO: Since bindings can exist between the SDU size and the
// protocol, we might need to throw an exception instead of just
// splitting the write into multiple smaller writes.
// Rfcomm uses dynamic allocation, and should not have any bindings
// to the actual message length.
if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
if (length <= mMaxTxPacketSize) {
mSocketOS.write(b, offset, length);
} else {
if (DBG) {
Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
+ "Packet will be divided into SDU packets of size "
+ mMaxTxPacketSize);
}
int tmpOffset = offset;
int bytesToWrite = length;
while (bytesToWrite > 0) {
int tmpLength = (bytesToWrite > mMaxTxPacketSize)
? mMaxTxPacketSize
: bytesToWrite;
mSocketOS.write(b, tmpOffset, tmpLength);
tmpOffset += tmpLength;
bytesToWrite -= tmpLength;
}
}
} else {
mSocketOS.write(b, offset, length);
}
// There is no good way to confirm since the entire process is asynchronous anyway
if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
return length;
}
之前在BluetoothOppTransfer.java中有调用mBtSocket.connect();
public void connect() throws IOException {
if (mDevice == null) throw new IOException("Connect is called on null device");
try {
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
IBluetooth bluetoothProxy =
BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
mUuid, mPort, getSecurityFlags());
synchronized (this) {
if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
if (mPfd == null) throw new IOException("bt socket connect failed");
FileDescriptor fd = mPfd.getFileDescriptor();
mSocket = LocalSocket.createConnectedLocalSocket(fd);
mSocketIS = mSocket.getInputStream();
mSocketOS = mSocket.getOutputStream();
}
int channel = readInt(mSocketIS);
if (channel <= 0) {
throw new IOException("bt socket connect failed");
}
mPort = channel;
waitSocketSignal(mSocketIS);
synchronized (this) {
if (mSocketState == SocketState.CLOSED) {
throw new IOException("bt socket closed");
}
mSocketState = SocketState.CONNECTED;
}
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
throw new IOException("unable to send RPC: " + e.getMessage());
}
}
IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
通过binder调用蓝牙AdapterService接口。
mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
mUuid, mPort, getSecurityFlags());
IBluetoothSocketManager getSocketManager() {
android.os.IBinder obj = getSocketManagerNative();
if (obj == null) {
return null;
}
return IBluetoothSocketManager.Stub.asInterface(obj);
}
Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
static jobject getSocketManagerNative(JNIEnv* env) {
std::lock_guard<std::mutex> lock(sSocketManagerMutex);
if (!sSocketManager.get()) {
sSocketManager =
new BluetoothSocketManagerBinderServer(sBluetoothSocketInterface);
}
return javaObjectForIBinder(env, IInterface::asBinder(sSocketManager));
}
Status BluetoothSocketManagerBinderServer::connectSocket(
const BluetoothDevice& device, int32_t type,
const std::unique_ptr<ParcelUuid>& uuid, int32_t port, int32_t flag,
std::unique_ptr<ParcelFileDescriptor>* _aidl_return) {
if (!isCallerActiveUserOrManagedProfile()) {
LOG(WARNING) << "connectSocket() - Not allowed for non-active users";
return Status::fromExceptionCode(
Status::EX_SECURITY, String8("Not allowed for non-active users"));
}
ENFORCE_PERMISSION(PERMISSION_BLUETOOTH);
IPCThreadState* ipc = IPCThreadState::self();
int socket_fd = -1;
bt_status_t status = socketInterface->connect(
&device.address, (btsock_type_t)type, uuid ? &uuid->uuid : nullptr, port,
&socket_fd, flag, ipc->getCallingUid());
if (status != BT_STATUS_SUCCESS) {
LOG(ERROR) << "Socket connection failed: " << +status;
socket_fd = -1;
}
if (socket_fd < 0) {
LOG(ERROR) << "Fail to create file descriptor on socket fd";
return Status::ok();
}
_aidl_return->reset(
new ParcelFileDescriptor(android::base::unique_fd(socket_fd)));
return Status::ok();
}
socketInterface是new BluetoothSocketManagerBinderServer(sBluetoothSocketInterface);中的sBluetoothSocketInterface
com_android_bluetooth_btservice_AdapterService.cpp
static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest,
jboolean isSingleUserMode) {
sBluetoothSocketInterface =
(btsock_interface_t*)sBluetoothInterface->get_profile_interface(
BT_PROFILE_SOCKETS_ID);
}
因此socketInterface->connect就调用了btif_sock.cc中的btsock_connect。
static bt_status_t btsock_connect(const RawAddress* bd_addr, btsock_type_t type,
const Uuid* uuid, int channel, int* sock_fd,
int flags, int app_uid) {
switch (type) {
case BTSOCK_RFCOMM:
status =
btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags, app_uid);
break;
case BTSOCK_L2CAP:
status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
break;
case BTSOCK_L2CAP_LE:
...
case BTSOCK_SCO:
...
default:
...
break;
}
return status;
}
这里应该是BTSOCK_L2CAP。
bt_status_t btsock_l2cap_connect(const RawAddress* bd_addr, int channel,
int* sock_fd, int flags, int app_uid) {
return btsock_l2cap_listen_or_connect(NULL, bd_addr, channel, sock_fd, flags,
0, app_uid);
}
static bt_status_t btsock_l2cap_listen_or_connect(const char* name,
const RawAddress* addr,
int channel, int* sock_fd,
int flags, char listen,
int app_uid) {
...
sock = btsock_l2cap_alloc_l(name, addr, listen, flags);
...
if (stat == BT_STATUS_SUCCESS) {
*sock_fd = sock->app_fd;
...
} else {
btsock_l2cap_free_l(sock);
}
return stat;
}
sock_fd即mPfd.getFileDescriptor()的返回值
static l2cap_socket* btsock_l2cap_alloc_l(const char* name,
const RawAddress* addr,
char is_server, int flags) {
...
if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, fds)) {
APPL_TRACE_ERROR("socketpair failed, errno:%d", errno);
goto fail_sockpair;
}
sock->our_fd = fds[0];
sock->app_fd = fds[1];
...
发送代码就追到这里
从log看应该是用btif_sock_l2cap.cc中的btsock_l2cap_signaled接收socket传来的数据。
void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
char drop_it = false;
/* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
* hold the lock. */
std::unique_lock<std::mutex> lock(state_lock);
l2cap_socket* sock = btsock_l2cap_find_by_id_l(user_id);
if (!sock) return;
if ((flags & SOCK_THREAD_FD_RD) && !sock->server) {
// app sending data
if (sock->connected) {
int size = 0;
bool ioctl_success = ioctl(sock->our_fd, FIONREAD, &size) == 0;
...
OSI_NO_INTR(count = recv(fd, buffer, size,
MSG_NOSIGNAL | MSG_DONTWAIT | MSG_TRUNC));
...
if (BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, count,
user_id) != BTA_JV_SUCCESS) {
}
}
}
bt/bta/jv/bta_jv_api.cc
tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id,
uint8_t* p_data, uint16_t len,
uint32_t user_id) {
tBTA_JV_STATUS status = BTA_JV_FAILURE;
APPL_TRACE_API("%s", __func__);
if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
tBTA_JV_API_L2CAP_WRITE* p_msg =
(tBTA_JV_API_L2CAP_WRITE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_WRITE));
p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT;
p_msg->handle = handle;
p_msg->req_id = req_id;
p_msg->p_data = p_data;
p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
p_msg->len = len;
p_msg->user_id = user_id;
bta_sys_sendmsg(p_msg);
status = BTA_JV_SUCCESS;
}
return status;
}
之后就是bluedroid中进行出来,最后发送cmd。