/* * 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. */ #ifndef ANDROID_HARDWARE_CONTEXTHUB_COMMON_MULTICLIENTS_HAL_BASE_H_ #define ANDROID_HARDWARE_CONTEXTHUB_COMMON_MULTICLIENTS_HAL_BASE_H_ #include #include #include #include #include "chre_connection_callback.h" #include "chre_host/napp_header.h" #include "chre_host/preloaded_nanoapp_loader.h" #include "chre_host/time_syncer.h" #include "context_hub_v4_impl.h" #include "debug_dump_helper.h" #include "event_logger.h" #include "hal_client_id.h" #include "hal_client_manager.h" #include #include #include #include #include #include #include #include namespace android::hardware::contexthub::common::implementation { using namespace aidl::android::hardware::contexthub; using namespace android::chre; using ::ndk::ScopedAStatus; /** * The base class of multiclient HAL. * *

A subclass should initiate mConnection, mHalClientManager and * mPreloadedNanoappLoader in its constructor. */ class MultiClientContextHubBase : public BnContextHub, public ::android::hardware::contexthub::common::implementation:: ChreConnectionCallback, public ::android::hardware::contexthub::DebugDumpHelper { public: /** The entry point of death recipient for a disconnected client. */ static void onClientDied(void *cookie); MultiClientContextHubBase(); // Functions implementing IContextHub. ScopedAStatus getContextHubs( std::vector *contextHubInfos) override; ScopedAStatus loadNanoapp(int32_t contextHubId, const NanoappBinary &appBinary, int32_t transactionId) override; ScopedAStatus unloadNanoapp(int32_t contextHubId, int64_t appId, int32_t transactionId) override; ScopedAStatus disableNanoapp(int32_t contextHubId, int64_t appId, int32_t transactionId) override; ScopedAStatus enableNanoapp(int32_t contextHubId, int64_t appId, int32_t transactionId) override; ScopedAStatus onSettingChanged(Setting setting, bool enabled) override; ScopedAStatus queryNanoapps(int32_t contextHubId) override; ScopedAStatus registerCallback( int32_t contextHubId, const std::shared_ptr &callback) override; ScopedAStatus sendMessageToHub(int32_t contextHubId, const ContextHubMessage &message) override; ScopedAStatus onHostEndpointConnected(const HostEndpointInfo &info) override; ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override; ScopedAStatus getPreloadedNanoappIds(int32_t contextHubId, std::vector *result) override; ScopedAStatus onNanSessionStateChanged( const NanSessionStateUpdate &in_update) override; ScopedAStatus setTestMode(bool enable) override; ScopedAStatus sendMessageDeliveryStatusToHub( int32_t contextHubId, const MessageDeliveryStatus &messageDeliveryStatus) override; ScopedAStatus getHubs(std::vector *hubs) override; ScopedAStatus getEndpoints(std::vector *endpoints) override; ScopedAStatus registerEndpointHub( const std::shared_ptr &callback, const HubInfo &hubInfo, std::shared_ptr *hubInterface) override; // Functions implementing ChreConnectionCallback. void handleMessageFromChre(const unsigned char *messageBuffer, size_t messageLen) override; void onChreRestarted() override; void onChreDisconnected() override; // Functions for dumping debug information. binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; bool requestDebugDump() override; void writeToDebugFile(const char *str) override; protected: // The timeout for a reliable message. constexpr static std::chrono::nanoseconds kReliableMessageTimeout = std::chrono::seconds(1); // The data needed by the death client to clear states of a client. struct HalDeathRecipientCookie { MultiClientContextHubBase *hal; pid_t clientPid; HalDeathRecipientCookie(MultiClientContextHubBase *hal, pid_t pid) { this->hal = hal; this->clientPid = pid; } }; // Contains information about a reliable message that has been received. struct ReliableMessageRecord { std::chrono::time_point timestamp; int32_t messageSequenceNumber; HostEndpointId hostEndpointId; bool isExpired() const { return timestamp + kReliableMessageTimeout < std::chrono::steady_clock::now(); } bool operator>(const ReliableMessageRecord &other) const { return timestamp > other.timestamp; } }; void tryTimeSync(size_t numOfRetries, useconds_t retryDelayUs) { if (mConnection->isTimeSyncNeeded()) { TimeSyncer::sendTimeSyncWithRetry(mConnection.get(), numOfRetries, retryDelayUs); } } bool sendFragmentedLoadRequest(HalClientId clientId, FragmentedLoadRequest &fragmentedLoadRequest); // Functions handling various types of messages void handleHubInfoResponse(const ::chre::fbs::HubInfoResponseT &message); void onNanoappListResponse(const ::chre::fbs::NanoappListResponseT &response, HalClientId clientid); void onNanoappLoadResponse(const ::chre::fbs::LoadNanoappResponseT &response, HalClientId clientId); void onNanoappUnloadResponse( const ::chre::fbs::UnloadNanoappResponseT &response, HalClientId clientId); void onNanoappMessage(const ::chre::fbs::NanoappMessageT &message); void onMessageDeliveryStatus( const ::chre::fbs::MessageDeliveryStatusT &status); void onDebugDumpData(const ::chre::fbs::DebugDumpDataT &data); void onDebugDumpComplete( const ::chre::fbs::DebugDumpResponseT & /* response */); void onMetricLog(const ::chre::fbs::MetricLogT &metricMessage); void handleClientDeath(pid_t pid); void handleLogMessageV2(const ::chre::fbs::LogMessageV2T &logMessage); /** * Enables test mode by unloading all the nanoapps except the system nanoapps. * Requires the caller to hold the mTestModeMutex. This function does not * set mIsTestModeEnabled. * * @return true as long as we have a list of nanoapps to unload. */ bool enableTestModeLocked(std::unique_lock &lock); /** * Enables test mode by unloading all the nanoapps except the system nanoapps. * * @return true as long as we have a list of nanoapps to unload. */ bool enableTestMode(); /** * Disables test mode by reloading all the preloaded nanoapps except * system nanoapps. * *

Note that dynamically loaded nanoapps that are unloaded during * enableTestMode() are not reloaded back because HAL doesn't track the * location of their binaries. */ void disableTestMode(); /** * Queries nanoapps from the context hub with the given client ID. * * @param contextHubId The context hub ID. * @param clientId The client ID. * @return A ScopedAStatus indicating the success or failure of the query. */ ScopedAStatus queryNanoappsWithClientId(int32_t contextHubId, HalClientId clientId); /** * Handles a nanoapp list response from the context hub for test mode * enablement. * * @param response The nanoapp list response from the context hub. */ void handleTestModeNanoappQueryResponse( const ::chre::fbs::NanoappListResponseT &response); inline bool isSettingEnabled(Setting setting) { return mSettingEnabled.find(setting) != mSettingEnabled.end() && mSettingEnabled[setting]; } /** * Removes messages from the reliable message queue that have been received * by the host more than kReliableMessageTimeout ago. */ void cleanupReliableMessageQueueLocked(); HalClientManager::DeadClientUnlinker mDeadClientUnlinker; std::shared_ptr mConnection{}; // HalClientManager maintains states of hal clients. Each HAL should only have // one instance of a HalClientManager. std::unique_ptr mHalClientManager{}; // Implementation of the V4+ API. Should be instantiated by the target HAL // implementation. std::optional mV4Impl{}; std::unique_ptr mPreloadedNanoappLoader{}; std::unique_ptr mContextHubInfo; // Mutex and CV are used to get context hub info synchronously. std::mutex mHubInfoMutex; std::condition_variable mHubInfoCondition; // Death recipient handling clients' disconnections ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; // States of settings std::unordered_map mSettingEnabled; std::optional mIsWifiAvailable; std::optional mIsBleAvailable; // A mutex to synchronize access to the list of preloaded nanoapp IDs. std::mutex mPreloadedNanoappIdsMutex; std::optional> mPreloadedNanoappIds{}; // test mode settings std::mutex mTestModeMutex; std::condition_variable mEnableTestModeCv; bool mIsTestModeEnabled = false; std::optional mTestModeSyncUnloadResult = std::nullopt; // mTestModeNanoapps records the nanoapps that will be unloaded in // enableTestMode(). std::optional> mTestModeNanoapps; // mTestModeSystemNanoapps records system nanoapps that won't be reloaded in // disableTestMode(). std::optional> mTestModeSystemNanoapps; EventLogger mEventLogger; // The parser of buffered logs from CHRE LogMessageParser mLogger; // Metrics reporter that will report metrics if it is initialized to non-null. std::unique_ptr mMetricsReporter; // Used to map message sequence number to host endpoint ID std::mutex mReliableMessageMutex; std::deque mReliableMessageQueue; // A thread safe flag indicating if CHRE is ready for operations. // Outside of the constructor, this boolean flag should only be written by // onChreDisconnected and onChreRestarted, the order of which should be // guaranteed by the CHRE's disconnection handler. std::atomic_bool mIsChreReady = true; // TODO(b/333567700): Remove when cleaning up the // bug_fix_hal_reliable_message_record flag std::unordered_map mReliableMessageMap; }; } // namespace android::hardware::contexthub::common::implementation #endif // ANDROID_HARDWARE_CONTEXTHUB_COMMON_MULTICLIENTS_HAL_BASE_H_