1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef CHRE_HOST_PRELOADED_NANOAPP_LOADER_H_ 18 #define CHRE_HOST_PRELOADED_NANOAPP_LOADER_H_ 19 20 #include <android/binder_to_string.h> 21 #include <atomic> 22 #include <cstdint> 23 #include <mutex> 24 #include <optional> 25 #include <string> 26 #include <utility> 27 28 #include "chre_connection.h" 29 30 #include "chre_host/generated/host_messages_generated.h" 31 #include "chre_host/log_message_parser.h" 32 #include "chre_host/metrics_reporter.h" 33 #include "chre_host/nanoapp_load_listener.h" 34 #include "chre_host/napp_header.h" 35 #include "event_logger.h" 36 #include "fragmented_load_transaction.h" 37 #include "hal_client_id.h" 38 39 namespace android::chre { 40 41 using namespace ::android::hardware::contexthub::common::implementation; 42 using ::aidl::android::hardware::contexthub::EventLogger; 43 44 /** 45 * A class loads preloaded nanoapps. 46 * 47 * A context hub can include a set of nanoapps that are included in the device 48 * image and are loaded when CHRE starts. These are known as preloaded nanoapps. 49 * A HAL implementation should use this class to load preloaded nanoapps before 50 * exposing API to HAL clients. 51 */ 52 class PreloadedNanoappLoader { 53 public: PreloadedNanoappLoader(ChreConnection * connection,EventLogger & eventLogger,MetricsReporter * metricsReporter,std::string configPath,INanoappLoadListener * nanoappLoadListener)54 explicit PreloadedNanoappLoader(ChreConnection *connection, 55 EventLogger &eventLogger, 56 MetricsReporter *metricsReporter, 57 std::string configPath, 58 INanoappLoadListener *nanoappLoadListener) 59 : mConnection(connection), 60 mEventLogger(eventLogger), 61 mMetricsReporter(metricsReporter), 62 mConfigPath(std::move(configPath)), 63 mNanoappLoadListener(nanoappLoadListener) {} 64 65 ~PreloadedNanoappLoader() = default; 66 /** 67 * Attempts to load all preloaded nanoapps from a config file. 68 * 69 * The config file is expected to be valid JSON with the following structure: 70 * 71 * { "nanoapps": [ 72 * "/path/to/nanoapp_1", 73 * "/path/to/nanoapp_2" 74 * ]} 75 * 76 * The napp_header and so files will both be used. 77 * 78 * @param skippedNanoappIds nanoapp ids identifying which nanoapps will NOT be 79 * loaded. 80 * 81 * @return the number of nanoapps loaded 82 */ 83 int loadPreloadedNanoapps(const std::optional<const std::vector<uint64_t>> 84 &skippedNanoappIds = std::nullopt); 85 86 /** Callback function to handle the response from CHRE. */ 87 bool onLoadNanoappResponse(const ::chre::fbs::LoadNanoappResponseT &response, 88 HalClientId clientId); 89 90 void getPreloadedNanoappIds(std::vector<uint64_t> &out_preloadedNanoappIds); 91 92 /** Returns true if the loading is ongoing. */ isPreloadOngoing()93 [[nodiscard]] bool isPreloadOngoing() const { 94 return mIsPreloadingOngoing; 95 } 96 97 private: 98 /** Tracks the transaction state of the ongoing nanoapp loading */ 99 struct Transaction { 100 uint32_t transactionId; 101 size_t fragmentId; 102 }; 103 104 /** The possible results of verification of a fragment load response. */ 105 enum class ResponseVerificationResult { 106 SUCCESS = 0, 107 FAILURE = 1, 108 IGNORED = 2, 109 }; 110 111 /** 112 * Loads a preloaded nanoapp. 113 * 114 * @param appHeader The nanoapp header binary blob. 115 * @param nanoappFileName The nanoapp binary file name. 116 * @param transactionId The transaction ID identifying this load transaction. 117 * @return true if successful, false otherwise. 118 */ 119 bool loadNanoapp(const NanoAppBinaryHeader *appHeader, 120 const std::string &nanoappFileName, uint32_t transactionId); 121 122 /** 123 * Chunks the nanoapp binary into fragments and load each fragment 124 * sequentially. 125 */ 126 bool sendFragmentedLoadAndWaitForEachResponse( 127 uint64_t appId, uint32_t appVersion, uint32_t appFlags, 128 uint32_t appTargetApiVersion, const uint8_t *appBinary, size_t appSize, 129 uint32_t transactionId); 130 131 /** Sends the FragmentedLoadRequest to CHRE. */ 132 std::future<bool> sendFragmentedLoadRequest( 133 ::android::chre::FragmentedLoadRequest &request); 134 135 /** Verifies the future returned by sendFragmentedLoadRequest(). */ 136 [[nodiscard]] bool waitAndVerifyFuture(std::future<bool> &future, 137 const FragmentedLoadRequest &request); 138 139 /** Verifies the response of a loading request. */ 140 [[nodiscard]] ResponseVerificationResult verifyFragmentLoadResponse( 141 const ::chre::fbs::LoadNanoappResponseT &response) const; 142 143 Transaction mPendingTransaction{/* transactionId= */ 0, 144 /* fragmentId= */ 0}; 145 146 /** The value of this promise carries the result in the load response. */ 147 std::optional<std::promise<bool>> mFragmentedLoadPromise = std::nullopt; 148 149 /** The mutex used to guard states change for preloading. */ 150 std::mutex mPreloadedNanoappsMutex; 151 152 std::atomic_bool mIsPreloadingOngoing = false; 153 154 ChreConnection *mConnection; 155 EventLogger &mEventLogger; 156 MetricsReporter *mMetricsReporter; 157 std::string mConfigPath; 158 159 INanoappLoadListener *mNanoappLoadListener; 160 }; 161 162 } // namespace android::chre 163 164 #endif // CHRE_HOST_PRELOADED_NANOAPP_LOADER_H_ 165