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   /**
105    * Loads a preloaded nanoapp.
106    *
107    * @param appHeader The nanoapp header binary blob.
108    * @param nanoappFileName The nanoapp binary file name.
109    * @param transactionId The transaction ID identifying this load transaction.
110    * @return true if successful, false otherwise.
111    */
112   bool loadNanoapp(const NanoAppBinaryHeader *appHeader,
113                    const std::string &nanoappFileName, uint32_t transactionId);
114 
115   /**
116    * Chunks the nanoapp binary into fragments and load each fragment
117    * sequentially.
118    */
119   bool sendFragmentedLoadAndWaitForEachResponse(
120       uint64_t appId, uint32_t appVersion, uint32_t appFlags,
121       uint32_t appTargetApiVersion, const uint8_t *appBinary, size_t appSize,
122       uint32_t transactionId);
123 
124   /** Sends the FragmentedLoadRequest to CHRE. */
125   std::future<bool> sendFragmentedLoadRequest(
126       ::android::chre::FragmentedLoadRequest &request);
127 
128   /** Verifies the future returned by sendFragmentedLoadRequest(). */
129   [[nodiscard]] bool waitAndVerifyFuture(std::future<bool> &future,
130                                          const FragmentedLoadRequest &request);
131 
132   /** Verifies the response of a loading request. */
133   [[nodiscard]] bool verifyFragmentLoadResponse(
134       const ::chre::fbs::LoadNanoappResponseT &response) const;
135 
136   Transaction mPreloadedNanoappPendingTransaction{0, 0};
137 
138   /** The value of this promise carries the result in the load response. */
139   std::optional<std::promise<bool>> mFragmentedLoadPromise = std::nullopt;
140 
141   /** The mutex used to guard states change for preloading. */
142   std::mutex mPreloadedNanoappsMutex;
143 
144   std::atomic_bool mIsPreloadingOngoing = false;
145 
146   ChreConnection *mConnection;
147   EventLogger &mEventLogger;
148   MetricsReporter *mMetricsReporter;
149   std::string mConfigPath;
150 
151   INanoappLoadListener *mNanoappLoadListener;
152 };
153 
154 }  // namespace android::chre
155 
156 #endif  // CHRE_HOST_PRELOADED_NANOAPP_LOADER_H_
157