/*
* 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.
*/
#include "chre_host/host_protocol_host.h"
#include <inttypes.h>
#include <string.h>
#include "chre_host/log.h"
using flatbuffers::FlatBufferBuilder;
using flatbuffers::Offset;
// Aliased for consistency with the way these symbols are referenced in
// CHRE-side code
namespace fbs = ::chre::fbs;
namespace android {
namespace chre {
// This is similar to getStringFromByteVector in host_protocol_chre.h. Ensure
// that method's implementation is kept in sync with this.
const char *getStringFromByteVector(const std::vector<int8_t>& vec) {
constexpr int8_t kNullChar = static_cast<int8_t>('\0');
const char *str = nullptr;
// Check that the vector is present, non-empty, and null-terminated
if (vec.size() > 0 && vec[vec.size() - 1] == kNullChar) {
str = reinterpret_cast<const char *>(vec.data());
}
return str;
}
bool HostProtocolHost::decodeMessageFromChre(
const void *message, size_t messageLen, IChreMessageHandlers& handlers) {
bool success = verifyMessage(message, messageLen);
if (success) {
std::unique_ptr<fbs::MessageContainerT> container =
fbs::UnPackMessageContainer(message);
fbs::ChreMessageUnion& msg = container->message;
switch (container->message.type) {
case fbs::ChreMessage::NanoappMessage:
handlers.handleNanoappMessage(*msg.AsNanoappMessage());
break;
case fbs::ChreMessage::HubInfoResponse:
handlers.handleHubInfoResponse(*msg.AsHubInfoResponse());
break;
case fbs::ChreMessage::NanoappListResponse:
handlers.handleNanoappListResponse(*msg.AsNanoappListResponse());
break;
case fbs::ChreMessage::LoadNanoappResponse:
handlers.handleLoadNanoappResponse(*msg.AsLoadNanoappResponse());
break;
case fbs::ChreMessage::UnloadNanoappResponse:
handlers.handleUnloadNanoappResponse(*msg.AsUnloadNanoappResponse());
break;
case fbs::ChreMessage::DebugDumpData:
handlers.handleDebugDumpData(*msg.AsDebugDumpData());
break;
case fbs::ChreMessage::DebugDumpResponse:
handlers.handleDebugDumpResponse(*msg.AsDebugDumpResponse());
break;
default:
LOGW("Got invalid/unexpected message type %" PRIu8,
static_cast<uint8_t>(msg.type));
success = false;
}
}
return success;
}
void HostProtocolHost::encodeHubInfoRequest(FlatBufferBuilder& builder) {
auto request = fbs::CreateHubInfoRequest(builder);
finalize(builder, fbs::ChreMessage::HubInfoRequest, request.Union());
}
void HostProtocolHost::encodeFragmentedLoadNanoappRequest(
flatbuffers::FlatBufferBuilder& builder,
const FragmentedLoadRequest& request) {
encodeLoadNanoappRequestForBinary(
builder, request.transactionId, request.appId, request.appVersion,
request.targetApiVersion, request.binary, request.fragmentId,
request.appTotalSizeBytes);
}
void HostProtocolHost::encodeNanoappListRequest(FlatBufferBuilder& builder) {
auto request = fbs::CreateNanoappListRequest(builder);
finalize(builder, fbs::ChreMessage::NanoappListRequest, request.Union());
}
void HostProtocolHost::encodeUnloadNanoappRequest(
FlatBufferBuilder& builder, uint32_t transactionId, uint64_t appId,
bool allowSystemNanoappUnload) {
auto request = fbs::CreateUnloadNanoappRequest(
builder, transactionId, appId, allowSystemNanoappUnload);
finalize(builder, fbs::ChreMessage::UnloadNanoappRequest, request.Union());
}
void HostProtocolHost::encodeTimeSyncMessage(FlatBufferBuilder& builder,
int64_t offset) {
auto request = fbs::CreateTimeSyncMessage(builder, offset);
finalize(builder, fbs::ChreMessage::TimeSyncMessage, request.Union());
}
void HostProtocolHost::encodeDebugDumpRequest(FlatBufferBuilder& builder) {
auto request = fbs::CreateDebugDumpRequest(builder);
finalize(builder, fbs::ChreMessage::DebugDumpRequest, request.Union());
}
bool HostProtocolHost::extractHostClientIdAndType(
const void *message, size_t messageLen, uint16_t *hostClientId,
::chre::fbs::ChreMessage *messageType) {
bool success = false;
if (hostClientId != nullptr && messageType != nullptr) {
success = verifyMessage(message, messageLen);
if (success) {
const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
// host_addr guaranteed to be non-null via verifyMessage (it's a required
// field)
*hostClientId = container->host_addr()->client_id();
*messageType = container->message_type();
}
}
return success;
}
bool HostProtocolHost::mutateHostClientId(void *message, size_t messageLen,
uint16_t hostClientId) {
bool success = verifyMessage(message, messageLen);
if (!success) {
LOGE("Message verification failed - can't mutate host ID");
} else {
fbs::MessageContainer *container = fbs::GetMutableMessageContainer(message);
// host_addr guaranteed to be non-null via verifyMessage (it's a required
// field)
container->mutable_host_addr()->mutate_client_id(hostClientId);
success = true;
}
return success;
}
void HostProtocolHost::encodeLoadNanoappRequestForBinary(
FlatBufferBuilder& builder, uint32_t transactionId, uint64_t appId,
uint32_t appVersion, uint32_t targetApiVersion,
const std::vector<uint8_t>& nanoappBinary, uint32_t fragmentId,
size_t appTotalSizeBytes) {
auto appBinary = builder.CreateVector(nanoappBinary);
auto request = fbs::CreateLoadNanoappRequest(
builder, transactionId, appId, appVersion, targetApiVersion, appBinary,
fragmentId, appTotalSizeBytes);
finalize(builder, fbs::ChreMessage::LoadNanoappRequest, request.Union());
}
void HostProtocolHost::encodeLoadNanoappRequestForFile(
flatbuffers::FlatBufferBuilder& builder, uint32_t transactionId,
uint64_t appId, uint32_t appVersion, uint32_t targetApiVersion,
const char *nanoappBinaryName) {
const std::vector<uint8_t> emptyAppBinary;
auto appBinary = builder.CreateVector(emptyAppBinary);
auto appBinaryName = addStringAsByteVector(builder, nanoappBinaryName);
auto request = fbs::CreateLoadNanoappRequest(
builder, transactionId, appId, appVersion, targetApiVersion, appBinary,
0 /* fragmentId */, 0 /* appTotalSizeBytes */, appBinaryName);
finalize(builder, fbs::ChreMessage::LoadNanoappRequest, request.Union());
}
} // namespace chre
} // namespace android