/* * 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/platform/shared/host_protocol_chre.h" #include #include #include "chre/platform/log.h" #include "chre/platform/shared/generated/host_messages_generated.h" using flatbuffers::Offset; using flatbuffers::Vector; namespace chre { // This is similar to getStringFromByteVector in host_protocol_host.h. Ensure // that method's implementation is kept in sync with this. const char *getStringFromByteVector(const flatbuffers::Vector *vec) { constexpr int8_t kNullChar = static_cast('\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; } bool HostProtocolChre::decodeMessageFromHost(const void *message, size_t messageLen) { bool success = verifyMessage(message, messageLen); if (!success) { LOGE("Dropping invalid/corrupted message from host (length %zu)", messageLen); } else { const fbs::MessageContainer *container = fbs::GetMessageContainer(message); uint16_t hostClientId = container->host_addr()->client_id(); 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(); HostMessageHandlers::handleNanoappMessage( nanoappMsg->app_id(), nanoappMsg->message_type(), nanoappMsg->host_endpoint(), msgData->data(), msgData->size()); break; } case fbs::ChreMessage::HubInfoRequest: HostMessageHandlers::handleHubInfoRequest(hostClientId); break; case fbs::ChreMessage::NanoappListRequest: HostMessageHandlers::handleNanoappListRequest(hostClientId); break; case fbs::ChreMessage::LoadNanoappRequest: { const auto *request = static_cast(container->message()); const flatbuffers::Vector *appBinary = request->app_binary(); const char *appBinaryFilename = getStringFromByteVector(request->app_binary_file_name()); HostMessageHandlers::handleLoadNanoappRequest( hostClientId, request->transaction_id(), request->app_id(), request->app_version(), request->app_flags(), request->target_api_version(), appBinary->data(), appBinary->size(), appBinaryFilename, request->fragment_id(), request->total_app_size(), request->respond_before_start()); break; } case fbs::ChreMessage::UnloadNanoappRequest: { const auto *request = static_cast( container->message()); HostMessageHandlers::handleUnloadNanoappRequest( hostClientId, request->transaction_id(), request->app_id(), request->allow_system_nanoapp_unload()); break; } case fbs::ChreMessage::TimeSyncMessage: { const auto *request = static_cast(container->message()); HostMessageHandlers::handleTimeSyncMessage(request->offset()); break; } case fbs::ChreMessage::DebugDumpRequest: HostMessageHandlers::handleDebugDumpRequest(hostClientId); break; case fbs::ChreMessage::SettingChangeMessage: { const auto *settingMessage = static_cast( container->message()); HostMessageHandlers::handleSettingChangeMessage( settingMessage->setting(), settingMessage->state()); break; } case fbs::ChreMessage::SelfTestRequest: { HostMessageHandlers::handleSelfTestRequest(hostClientId); break; } default: LOGW("Got invalid/unexpected message type %" PRIu8, static_cast(container->message_type())); success = false; } } return success; } void HostProtocolChre::encodeHubInfoResponse( ChreFlatBufferBuilder &builder, const char *name, const char *vendor, const char *toolchain, uint32_t legacyPlatformVersion, uint32_t legacyToolchainVersion, float peakMips, float stoppedPower, float sleepPower, float peakPower, uint32_t maxMessageLen, uint64_t platformId, uint32_t version, uint16_t hostClientId) { auto nameOffset = addStringAsByteVector(builder, name); auto vendorOffset = addStringAsByteVector(builder, vendor); auto toolchainOffset = addStringAsByteVector(builder, toolchain); auto response = fbs::CreateHubInfoResponse( builder, nameOffset, vendorOffset, toolchainOffset, legacyPlatformVersion, legacyToolchainVersion, peakMips, stoppedPower, sleepPower, peakPower, maxMessageLen, platformId, version); finalize(builder, fbs::ChreMessage::HubInfoResponse, response.Union(), hostClientId); } void HostProtocolChre::addNanoappListEntry( ChreFlatBufferBuilder &builder, DynamicVector> &offsetVector, uint64_t appId, uint32_t appVersion, bool enabled, bool isSystemNanoapp, uint32_t appPermissions) { auto offset = fbs::CreateNanoappListEntry(builder, appId, appVersion, enabled, isSystemNanoapp, appPermissions); if (!offsetVector.push_back(offset)) { LOGE("Couldn't push nanoapp list entry offset!"); } } void HostProtocolChre::finishNanoappListResponse( ChreFlatBufferBuilder &builder, DynamicVector> &offsetVector, uint16_t hostClientId) { auto vectorOffset = builder.CreateVector>(offsetVector); auto response = fbs::CreateNanoappListResponse(builder, vectorOffset); finalize(builder, fbs::ChreMessage::NanoappListResponse, response.Union(), hostClientId); } void HostProtocolChre::encodeLoadNanoappResponse(ChreFlatBufferBuilder &builder, uint16_t hostClientId, uint32_t transactionId, bool success, uint32_t fragmentId) { auto response = fbs::CreateLoadNanoappResponse(builder, transactionId, success, fragmentId); finalize(builder, fbs::ChreMessage::LoadNanoappResponse, response.Union(), hostClientId); } void HostProtocolChre::encodeUnloadNanoappResponse( ChreFlatBufferBuilder &builder, uint16_t hostClientId, uint32_t transactionId, bool success) { auto response = fbs::CreateUnloadNanoappResponse(builder, transactionId, success); finalize(builder, fbs::ChreMessage::UnloadNanoappResponse, response.Union(), hostClientId); } void HostProtocolChre::encodeLogMessages(ChreFlatBufferBuilder &builder, const uint8_t *logBuffer, size_t bufferSize) { auto logBufferOffset = builder.CreateVector( reinterpret_cast(logBuffer), bufferSize); auto message = fbs::CreateLogMessage(builder, logBufferOffset); finalize(builder, fbs::ChreMessage::LogMessage, message.Union()); } void HostProtocolChre::encodeLogMessagesV2(ChreFlatBufferBuilder &builder, const uint8_t *logBuffer, size_t bufferSize, uint32_t numLogsDropped) { auto logBufferOffset = builder.CreateVector( reinterpret_cast(logBuffer), bufferSize); auto message = fbs::CreateLogMessageV2(builder, logBufferOffset, numLogsDropped); finalize(builder, fbs::ChreMessage::LogMessageV2, message.Union()); } void HostProtocolChre::encodeDebugDumpData(ChreFlatBufferBuilder &builder, uint16_t hostClientId, const char *debugStr, size_t debugStrSize) { auto debugStrOffset = builder.CreateVector( reinterpret_cast(debugStr), debugStrSize); auto message = fbs::CreateDebugDumpData(builder, debugStrOffset); finalize(builder, fbs::ChreMessage::DebugDumpData, message.Union(), hostClientId); } void HostProtocolChre::encodeDebugDumpResponse(ChreFlatBufferBuilder &builder, uint16_t hostClientId, bool success, uint32_t dataCount) { auto response = fbs::CreateDebugDumpResponse(builder, success, dataCount); finalize(builder, fbs::ChreMessage::DebugDumpResponse, response.Union(), hostClientId); } void HostProtocolChre::encodeTimeSyncRequest(ChreFlatBufferBuilder &builder) { auto request = fbs::CreateTimeSyncRequest(builder); finalize(builder, fbs::ChreMessage::TimeSyncRequest, request.Union()); } void HostProtocolChre::encodeLowPowerMicAccessRequest( ChreFlatBufferBuilder &builder) { auto request = fbs::CreateLowPowerMicAccessRequest(builder); finalize(builder, fbs::ChreMessage::LowPowerMicAccessRequest, request.Union()); } void HostProtocolChre::encodeLowPowerMicAccessRelease( ChreFlatBufferBuilder &builder) { auto request = fbs::CreateLowPowerMicAccessRelease(builder); finalize(builder, fbs::ChreMessage::LowPowerMicAccessRelease, request.Union()); } void HostProtocolChre::encodeSelfTestResponse(ChreFlatBufferBuilder &builder, uint16_t hostClientId, bool success) { auto response = fbs::CreateSelfTestResponse(builder, success); finalize(builder, fbs::ChreMessage::SelfTestResponse, response.Union(), hostClientId); } bool HostProtocolChre::getSettingFromFbs(fbs::Setting setting, Setting *chreSetting) { bool success = true; switch (setting) { case fbs::Setting::LOCATION: *chreSetting = Setting::LOCATION; break; case fbs::Setting::WIFI_AVAILABLE: *chreSetting = Setting::WIFI_AVAILABLE; break; case fbs::Setting::AIRPLANE_MODE: *chreSetting = Setting::AIRPLANE_MODE; break; case fbs::Setting::MICROPHONE: *chreSetting = Setting::MICROPHONE; break; default: LOGE("Unknown setting %" PRIu8, static_cast(setting)); success = false; } return success; } bool HostProtocolChre::getSettingStateFromFbs(fbs::SettingState state, SettingState *chreSettingState) { bool success = true; switch (state) { case fbs::SettingState::DISABLED: *chreSettingState = SettingState::DISABLED; break; case fbs::SettingState::ENABLED: *chreSettingState = SettingState::ENABLED; break; default: LOGE("Unknown state %" PRIu8, static_cast(state)); success = false; } return success; } } // namespace chre