blob: b6c6843c552093faf7b072d5987568ec30833652 [file] [log] [blame]
// Copyright 2018 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/emulation/AdbMessageSniffer.h"
#include "android/globals.h"
#include <atomic>
static std::atomic<int> host_cts_heart_beat_count {};
namespace android {
namespace emulation {
// the following definition is defined in system/core/adb
#define ADB_SYNC 0x434e5953
#define ADB_CNXN 0x4e584e43
#define ADB_OPEN 0x4e45504f
#define ADB_OKAY 0x59414b4f
#define ADB_CLSE 0x45534c43
#define ADB_WRTE 0x45545257
#define ADB_AUTH 0x48545541
#define ADB_AUTH_TOKEN 1
#define ADB_AUTH_SIGNATURE 2
#define ADB_AUTH_RSAPUBLICKEY 3
#define ADB_VERSION 0x01000000
// 1 MB
#define MAX_ADB_MESSAGE_PAYLOAD 1048576
AdbMessageSniffer::AdbMessageSniffer(const char* name):mName(name) {
memset(&mPacket, 0, sizeof(apacket));
mBufferVec.resize(MAX_ADB_MESSAGE_PAYLOAD);
startNewMessage();
}
AdbMessageSniffer::~AdbMessageSniffer() {
}
void AdbMessageSniffer::grow_buffer_if_needed(int count) {
if (mBufferVec.size() < count) {
mBufferVec.resize(2 * count);
}
mBuffer = static_cast<uint8_t*> (&(mBufferVec[0]));
}
void AdbMessageSniffer::readToBuffer(const AndroidPipeBuffer* buffers, int numBuffers, int count) {
mBufferP = mBuffer;
for (int i=0; i < numBuffers; ++i) {
uint8_t* data = buffers[i].data;
int dataSize = buffers[i].size;
if (count < dataSize) {
memcpy(mBufferP, data, count);
return;
} else {
memcpy(mBufferP, data, dataSize);
mBufferP += dataSize;
count -= dataSize;
if (count <= 0) {
return;
}
}
}
}
void AdbMessageSniffer::parseBuffer(int bufferLength) {
mBufferP = mBuffer;
int count = bufferLength;
while (count > 0) {
if (mState == 0) {
count -= readHeader(count);
} else {
count -= readPayload(count);
}
}
}
int AdbMessageSniffer::readHeader(int dataSize) {
CHECK( mPacket.data - mCurrPos > 0);
int need = sizeof(amessage) - (mCurrPos - (uint8_t*)(&mPacket));
if (need > dataSize) {
copyFromBuffer(dataSize);
return dataSize;
} else {
copyFromBuffer(need);
updateCtsHeartBeatCount();
printMessage();
mState = 1;
return need;
}
}
void AdbMessageSniffer::updateCtsHeartBeatCount() {
amessage & msg = mPacket.mesg;
// OKAY is usually from logcat, ignore it
if (msg.command != ADB_OKAY) {
host_cts_heart_beat_count += 1;
}
}
void AdbMessageSniffer::checkForShellExit() {
amessage & msg = mPacket.mesg;
if (msg.command == ADB_OPEN) {
mPacket.data[msg.data_length] = '\0';
const char *purpose = (char*)(mPacket.data);
if (strncmp(purpose, "shell", 5)==0) {
if (strstr(purpose, ":exit") != NULL) {
//found shell exit
printf("found shell %s\n", purpose);
}
}
}
}
int AdbMessageSniffer::readPayload(int dataSize) {
CHECK(mCurrPos - mPacket.data >= 0);
int need = getPayloadSize() - (mCurrPos - mPacket.data);
if (need > dataSize) {
copyFromBuffer(dataSize);
return dataSize;
} else {
copyFromBuffer(need);
checkForShellExit();
printPayload();
startNewMessage();
return need;
}
}
void AdbMessageSniffer::read(const AndroidPipeBuffer* buffers, int numBuffers, int count) {
if (count <= 0) return;
grow_buffer_if_needed(count);
readToBuffer(buffers, numBuffers, count);
parseBuffer(count);
}
int AdbMessageSniffer::getPayloadSize() {
return mPacket.mesg.data_length;
}
void AdbMessageSniffer::copyFromBuffer(int count) {
// guard against overflow
int avail = sizeof(mPacket) - (mCurrPos - mPacket.data) - sizeof(mPacket.mesg);
if (avail > 0 ) {
int size = std::min(avail, count);
memcpy(mCurrPos, mBufferP, size);
}
mCurrPos += count;
mBufferP += count;
}
int AdbMessageSniffer::getAllowedBytesToPrint(int bytes) {
int allowed = std::min(bytes, (int)(sizeof(mPacket.data)));
return allowed;
}
void AdbMessageSniffer::printPayload() {
if (android_hw->test_monitorAdb< 2 ) {
return;
}
amessage & msg = mPacket.mesg;
if ( msg.command == ADB_OKAY
|| msg.command == ADB_WRTE) {
return;
}
int length = msg.data_length;
length = getAllowedBytesToPrint(length);
if (length <= 0 ) return;
uint8_t* data = mPacket.data;
for (int i=0; i < length; ++i) {
if (i % 1024 == 0) {
printf("%s:", mName);
}
int ch = data[i];
if (isprint(ch)) {
printf("%c", ch);
} else if (isspace(ch)) {
//printf("%c", ch);
} else {
//printf(" ");
}
}
printf("\n");
}
const char* AdbMessageSniffer::getCommandName(unsigned code) {
switch(code) {
case ADB_SYNC:
return "SYNC";
case ADB_CNXN:
return "CNXN";
case ADB_OPEN:
return "OPEN";
case ADB_CLSE:
return "CLOSE";
case ADB_AUTH:
return "AUTH";
case ADB_WRTE:
return "WRITE";
case ADB_OKAY:
return "OKAY";
default:
return "unknown";
}
}
void AdbMessageSniffer::printMessage() {
if (android_hw->test_monitorAdb < 2 ) {
return;
}
amessage & msg = mPacket.mesg;
if ( msg.command == ADB_OKAY
|| msg.command == ADB_WRTE) {
return;
}
printf("%s:command: %s ", mName, getCommandName(msg.command));
printf("arg0: %d ", msg.arg0);
printf("arg1: %d ", msg.arg1);
printf("data length: %d\n", msg.data_length);
}
void AdbMessageSniffer::startNewMessage() {
mCurrPos = (uint8_t*)(&mPacket);
mState = 0;
}
} // namespace emulation
} // namespace android
extern "C" int get_host_cts_heart_beat_count(void) {
return host_cts_heart_beat_count.load();
}