/* * Copyright (C) 2022 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/host_link.h" #include "chre/core/event_loop_manager.h" #include "chre/core/host_comms_manager.h" #include "chre/platform/shared/host_protocol_chre.h" #include "chre/platform/shared/nanoapp_load_manager.h" #include "chre/platform/system_time.h" #include "chre/platform/system_timer.h" #include "chre/util/flatbuffers/helpers.h" #include "chre/util/nested_data_ptr.h" #include "include/chre/target_platform/host_link_base.h" #include "mailbox.h" // The delete operator is generated by the compiler but not actually called, // empty implementations are provided to avoid linker warnings. void operator delete(void * /*ptr*/) {} void operator delete(void * /*ptr*/, size_t /*sz*/) {} namespace chre { namespace { struct UnloadNanoappCallbackData { uint64_t appId; uint32_t transactionId; uint16_t hostClientId; bool allowSystemNanoappUnload; }; inline HostCommsManager &getHostCommsManager() { return EventLoopManagerSingleton::get()->getHostCommsManager(); } void setTimeSyncRequestTimer(Nanoseconds delay) { static TimerHandle sHandle; static bool sHandleInitialized; if (sHandleInitialized) { EventLoopManagerSingleton::get()->cancelDelayedCallback(sHandle); } auto callback = [](uint16_t /*type*/, void * /*data*/, void * /*extraData*/) { HostLinkBase::sendTimeSyncRequest(); }; sHandle = EventLoopManagerSingleton::get()->setDelayedCallback( SystemCallbackType::TimerSyncRequest, nullptr /*data*/, callback, delay); sHandleInitialized = true; } } // anonymous namespace void sendDebugDumpResultToHost(uint16_t /*hostClientId*/, const char * /*debugStr*/, size_t /*debugStrSize*/, bool /*complete*/, uint32_t /*dataCount*/) { // TODO(b/230134803): Implement this. } HostLinkBase::HostLinkBase() { int32_t rv = mailboxReadChre(mMsgBuffer, CHRE_MESSAGE_TO_HOST_MAX_SIZE, receive, this /*cookie*/); CHRE_ASSERT_LOG((rv == 0), "Failed to register inbound message handler %" PRId32, rv); } void HostLinkBase::receive(void *cookie, void *message, int messageLen) { auto *instance = static_cast(cookie); // TODO(b/237819962): A crude way to initially determine daemon's up - set // a flag on the first message received. This is temporary until a better // way to do this is available. instance->setInitialized(true); if (!HostProtocolChre::decodeMessageFromHost(message, messageLen)) { LOGE("Failed to decode msg %p of len %zu", message, messageLen); } } bool HostLink::sendMessage(const MessageToHost *message) { bool success = false; if (isInitialized()) { constexpr size_t kFixedReserveSize = 88; ChreFlatBufferBuilder builder(message->message.size() + kFixedReserveSize); HostProtocolChre::encodeNanoappMessage( builder, message->appId, message->toHostData.messageType, message->toHostData.hostEndpoint, message->message.data(), message->message.size(), message->toHostData.appPermissions, message->toHostData.messagePermissions, message->toHostData.wokeHost, message->isReliable, message->messageSequenceNumber); success = (send(builder.GetBufferPointer(), builder.GetSize()) == 0); // Only invoke on success as returning false from this method will cause // core logic to do the appropriate cleanup. if (success) { EventLoopManagerSingleton::get() ->getHostCommsManager() .onMessageToHostComplete(message); } } else { LOGW("Dropping outbound message: host link not initialized yet"); } return success; } bool HostLink::sendMessageDeliveryStatus(uint32_t /* messageSequenceNumber */, uint8_t /* errorCode */) { return false; } // TODO(b/239096709): HostMessageHandlers member function implementations are // expected to be (mostly) identical for any platform that uses flatbuffers // to encode messages - refactor the host link to merge the multiple copies // we currently have. void HostMessageHandlers::handleNanoappMessage( uint64_t appId, uint32_t messageType, uint16_t hostEndpoint, const void * /* messageData */, size_t messageDataLen, bool /* isReliable */, uint32_t /* messageSequenceNumber */) { LOGD("Parsed nanoapp message from host: app ID 0x%016" PRIx64 ", endpoint " "0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu", appId, hostEndpoint, messageType, messageDataLen); // TODO(b/230134803): Implement this. } void HostMessageHandlers::handleMessageDeliveryStatus( uint32_t /* messageSequenceNumber */, uint8_t /* errorCode */) {} void HostMessageHandlers::handleHubInfoRequest(uint16_t /* hostClientId */) { // TODO(b/230134803): Implement this. } void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) { // TODO(b/230134803): Implement this. } void HostMessageHandlers::handlePulseRequest() {} void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId, uint32_t transactionId, uint32_t fragmentId, bool success) { constexpr size_t kInitialBufferSize = 52; ChreFlatBufferBuilder builder(kInitialBufferSize); HostProtocolChre::encodeLoadNanoappResponse( builder, hostClientId, transactionId, success, fragmentId); if (!getHostCommsManager().send(builder.GetBufferPointer(), builder.GetSize())) { LOGE("Failed to send fragment response for HostClientID: %" PRIx16 " , FragmentID: %" PRIx32 " transactionID: %" PRIx32, hostClientId, fragmentId, transactionId); } } void HostMessageHandlers::handleLoadNanoappRequest( uint16_t hostClientId, uint32_t transactionId, uint64_t appId, uint32_t appVersion, uint32_t appFlags, uint32_t targetApiVersion, const void *buffer, size_t bufferLen, const char *appFileName, uint32_t fragmentId, size_t appBinaryLen, bool respondBeforeStart) { UNUSED_VAR(appFileName); loadNanoappData(hostClientId, transactionId, appId, appVersion, appFlags, targetApiVersion, buffer, bufferLen, fragmentId, appBinaryLen, respondBeforeStart); } void HostMessageHandlers::handleUnloadNanoappRequest( uint16_t hostClientId, uint32_t transactionId, uint64_t appId, bool allowSystemNanoappUnload) { LOGD("Unload nanoapp request from client %" PRIu16 " (txnID %" PRIu32 ") for appId 0x%016" PRIx64 " system %d", hostClientId, transactionId, appId, allowSystemNanoappUnload); // TODO(b/230134803): Implement this. } void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) { LOGD("Time sync msg received with offset %" PRId64, offset); SystemTime::setEstimatedHostTimeOffset(offset); // Schedule a time sync request since offset may drift constexpr Seconds kClockDriftTimeSyncPeriod = Seconds(60 * 60 * 6); // 6 hours setTimeSyncRequestTimer(kClockDriftTimeSyncPeriod); } void HostMessageHandlers::handleDebugDumpRequest(uint16_t /* hostClientId */) { // TODO(b/230134803): Implement this. } void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting, fbs::SettingState state) { Setting chreSetting; bool chreSettingEnabled; if (HostProtocolChre::getSettingFromFbs(setting, &chreSetting) && HostProtocolChre::getSettingEnabledFromFbs(state, &chreSettingEnabled)) { EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( chreSetting, chreSettingEnabled); } } void HostMessageHandlers::handleSelfTestRequest(uint16_t /* hostClientId */) { // TODO(b/230134803): Implement this. } void HostMessageHandlers::handleNanConfigurationUpdate(bool /* enabled */) { LOGE("NAN unsupported."); } } // namespace chre