blob: f9e9db8ccfbb5cbd19335040b14ada16b4ffe76e [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdlib.h>
#include <cutils/sockets.h>
#include <log/log.h>
#include "common/libs/fs/shared_fd.h"
// #define DEBUG_CONNECTIONS
/*
* Packet structures for commands sent to the remoter from the GCE HAL.
* This is a private protocol between the HAL and the remoter.
*/
static const size_t kSensorNameMaxLen = 64;
// Don't use PATH_MAX here because it would increate the size of every
// packet that we send to the remoter.
static const size_t kScreenRecordFilePathMaxLen = 128;
static const size_t kUnixSocketPathMaxLen = 128;
struct remoter_request_packet {
/* Length of the packet in bytes. */
uint32_t length;
/* Operation to perform. */
uint8_t operation;
/* Set to '1' if a response packet is desired */
uint8_t send_response;
/* Operation arguments. */
union {
/* Arguments for the frame buffer 'post' operation. */
struct {
/* Y offset in the double-buffer where this frame starts. */
uint32_t y_offset;
} fb_post_params;
/* Arguments for the frame buffer 'update rect' operation. */
struct {
uint32_t left;
uint32_t top;
uint32_t width;
uint32_t height;
} fb_update_rect_params;
struct {
uint32_t type;
bool enabled;
int64_t delay_ns;
int handle;
} sensor_state_params;
struct {
char filepath[kScreenRecordFilePathMaxLen];
} screenrecord_params;
struct {
char unix_socket[kUnixSocketPathMaxLen];
} hal_ready_params;
} params;
} __attribute__((packed));
enum {
kRemoterHALReady = 1,
kRemoterSensorState
};
/*
* If 'send_response' is set in a request then the remoter will respond
* with the following structure.
*/
struct remoter_response_packet {
uint32_t length;
uint8_t status;
union {
struct {
/* Number of 'struct sensor_list_element_packet's to follow */
uint8_t num_sensors;
} sensor_list_data;
} data;
} __attribute__((packed));
struct sensor_list_element_packet {
int handle;
int type;
char name[kSensorNameMaxLen];
char vendor[kSensorNameMaxLen];
int version;
float max_range;
float resolution;
float power;
} __attribute__((packed));
enum {
kResponseStatusOk = 1,
kResponseStatusFailed
};
static inline void remoter_request_packet_init(
struct remoter_request_packet* pkt, uint8_t operation,
uint8_t send_response) {
memset(pkt, 0, sizeof(*pkt));
pkt->length = sizeof(*pkt);
pkt->operation = operation;
pkt->send_response = send_response;
}
static inline void remoter_response_packet_init(
struct remoter_response_packet* pkt, uint8_t status) {
memset(pkt, 0, sizeof(*pkt));
pkt->length = sizeof(*pkt);
pkt->status = status;
}
void remoter_connect(cvd::SharedFD* dest);
int remoter_connect();
static inline int remoter_read_request(
const cvd::SharedFD& socket,
struct remoter_request_packet* request) {
int len;
int remaining_data;
/* Packets start with a 4 byte length (which includes the length). */
if ((len = socket->Read(request, sizeof(request->length))) < 0) {
ALOGE("%s: Failed to read remoter request (%s)",
__FUNCTION__, socket->StrError());
return -1;
} else if (len == 0) {
return 0;
} else if (len != sizeof(request->length)) {
ALOGE("%s: Failed to read remoter request (Short read)", __FUNCTION__);
return -1;
}
/* Extra paranoia. */
if (request->length != sizeof(*request)) {
ALOGE("%s: Malformed remoter request", __FUNCTION__);
return -1;
}
remaining_data = request->length - sizeof(request->length);
uint8_t* cursor = ((uint8_t*)request) + sizeof(request->length);
if ((len = socket->Read(cursor, remaining_data)) < 0) {
ALOGE("%s: Failed to read remoter request (%s)",
__FUNCTION__, socket->StrError());
return -1;
} else if (len == 0) {
return 0;
} else if (len != (int) remaining_data) {
ALOGE("%s: Failed to read remoter request (Short read)", __FUNCTION__);
return -1;
}
return 1;
}
static inline int remoter_read_response(
int socket, struct remoter_response_packet* response) {
int len;
int remaining_data;
/* Packets start with a 4 byte length (which includes the length). */
#ifdef DEBUG_CONNECTIONS
ALOGI("remoter_read_response(): socket %d, length length = %d", socket,
sizeof(response->length));
#endif
if ((len = TEMP_FAILURE_RETRY(
read(socket, response, sizeof(response->length)))) < 0) {
ALOGE("%s: Failed to read remoter response (%s)",
__FUNCTION__, strerror(errno));
return -1;
} else if (len == 0) {
return 0;
} else if (len != sizeof(response->length)) {
ALOGE("%s: Failed to read remoter response (Short read)", __FUNCTION__);
return -1;
}
/* Extra paranoia. */
if (response->length != sizeof(*response)) {
ALOGE("%s: Malformed remoter response", __FUNCTION__);
return -1;
}
remaining_data = response->length - sizeof(response->length);
uint8_t* cursor = ((uint8_t*)response) + sizeof(response->length);
#ifdef DEBUG_CONNECTIONS
ALOGI("remoter_read_request(): socket %d, data length = %d",
socket, remaining_data);
#endif
if ((len = TEMP_FAILURE_RETRY(read(socket, cursor, remaining_data))) < 0) {
ALOGE("%s: Failed to read remoter response (%s)",
__FUNCTION__, strerror(errno));
return -1;
} else if (len == 0) {
return 0;
} else if (len != (int) remaining_data) {
ALOGE("%s: Failed to read remoter response (Short read)", __FUNCTION__);
return -1;
}
return 1;
}
static inline int remoter_send_request(
int socket, struct remoter_request_packet* request) {
#ifdef DEBUG_CONNECTIONS
ALOGI(
"remoter_send_request(): socket %d, length %u", socket, sizeof(*request));
#endif
int len = TEMP_FAILURE_RETRY(write(socket, request, sizeof(*request)));
if (len <= 0) {
ALOGE("Failed to write request to remoter (%s)", strerror(errno));
return -1;
} else if (len != sizeof(*request)) {
ALOGE("Failed to write request to remoter (short write)");
return -1;
}
return 0;
}
static inline int remoter_send_response(
const cvd::SharedFD& socket,
struct remoter_response_packet* response) {
int len = socket->Write(response, sizeof(*response));
if (len <=0) {
ALOGE("%s: Failed to send response to remoter (%s)",
__FUNCTION__, strerror(errno));
return -1;
}
return 0;
}
static inline int remoter_do_single_request_with_socket(
int socket, struct remoter_request_packet* request,
struct remoter_response_packet* response) {
if (request->send_response && !response) {
ALOGE("%s: Request specifies a response but no response ptr set",
__FUNCTION__);
return -1;
} else if (!request->send_response && response) {
ALOGE("%s: Request specifies no response but has response ptr set",
__FUNCTION__);
return -1;
}
if (remoter_send_request(socket, request) < 0) {
return -1;
}
if (response && (remoter_read_response(socket, response) <= 0)) {
return -1;
}
return 0;
}
static inline int remoter_do_single_request(
struct remoter_request_packet* request,
struct remoter_response_packet* response) {
int socket;
if ((socket = remoter_connect()) < 0) {
return -1;
}
if (remoter_do_single_request_with_socket(socket, request, response) < 0) {
close(socket);
return -1;
}
close(socket);
return 0;
}