/* * 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 #include #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 { namespace { /** * Checks that a string encapsulated as a byte vector is null-terminated, and * if it is, returns a pointer to the vector's data. Otherwise returns null. * * @param vec Target vector, can be null * * @return Pointer to the vector's data, or null */ const char *getStringFromByteVector(const flatbuffers::Vector *vec) { constexpr int8_t kNullChar = 0; const char *str = nullptr; // Check that the vector is present, non-empty, and null-terminated if (vec != nullptr && vec->size() > 0 && (*vec)[vec->size() - 1] == kNullChar) { str = reinterpret_cast(vec->data()); } return str; } } // anonymous namespace bool HostProtocolHost::decodeMessageFromChre( const void *message, size_t messageLen, IChreMessageHandlers& handlers) { bool success = verifyMessage(message, messageLen); if (success) { const fbs::MessageContainer *container = fbs::GetMessageContainer(message); switch (container->message_type()) { case fbs::ChreMessage::NanoappMessage: { const auto *nanoappMsg = static_cast( container->message()); // Required field; verifier ensures that this is not null (though it // may be empty) const flatbuffers::Vector *msgData = nanoappMsg->message(); handlers.handleNanoappMessage( nanoappMsg->app_id(), nanoappMsg->message_type(), nanoappMsg->host_endpoint(), msgData->data(), msgData->size()); break; } case fbs::ChreMessage::HubInfoResponse: { const auto *resp = static_cast( container->message()); const char *name = getStringFromByteVector(resp->name()); const char *vendor = getStringFromByteVector(resp->vendor()); const char *toolchain = getStringFromByteVector(resp->toolchain()); handlers.handleHubInfoResponse( name, vendor, toolchain, resp->platform_version(), resp->toolchain_version(), resp->peak_mips(), resp->stopped_power(), resp->sleep_power(), resp->peak_power(), resp->max_msg_len(), resp->platform_id(), resp->chre_platform_version()); break; } case fbs::ChreMessage::NanoappListResponse: { const auto *resp = static_cast( container->message()); fbs::NanoappListResponseT response; resp->UnPackTo(&response); handlers.handleNanoappListResponse(response); break; } case fbs::ChreMessage::LoadNanoappResponse: { const auto *resp = static_cast( container->message()); fbs::LoadNanoappResponseT response; resp->UnPackTo(&response); handlers.handleLoadNanoappResponse(response); break; } default: LOGW("Got invalid/unexpected message type %" PRIu8, static_cast(container->message_type())); success = false; } } return success; } void HostProtocolHost::encodeHubInfoRequest(FlatBufferBuilder& builder) { auto request = fbs::CreateHubInfoRequest(builder); finalize(builder, fbs::ChreMessage::HubInfoRequest, request.Union()); } void HostProtocolHost::encodeLoadNanoappRequest( FlatBufferBuilder& builder, uint32_t transactionId, uint64_t appId, uint32_t appVersion, uint32_t targetApiVersion, const std::vector& nanoappBinary) { auto appBinary = builder.CreateVector(nanoappBinary); auto request = fbs::CreateLoadNanoappRequest( builder, transactionId, appId, appVersion, targetApiVersion, appBinary); finalize(builder, fbs::ChreMessage::LoadNanoappRequest, request.Union()); } void HostProtocolHost::encodeNanoappListRequest(FlatBufferBuilder& builder) { auto request = fbs::CreateNanoappListRequest(builder); finalize(builder, fbs::ChreMessage::NanoappListRequest, request.Union()); } bool HostProtocolHost::extractHostClientId(const void *message, size_t messageLen, uint16_t *hostClientId) { bool success = verifyMessage(message, messageLen); if (success && hostClientId != nullptr) { 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(); success = true; } 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; } } // namespace chre } // namespace android