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_EXYNOS_DAEMON_H_
18 #define CHRE_EXYNOS_DAEMON_H_
19 
20 #include <atomic>
21 #include <thread>
22 
23 #include "chre_host/fbs_daemon_base.h"
24 #include "chre_host/st_hal_lpma_handler.h"
25 
26 namespace android {
27 namespace chre {
28 
29 class ExynosDaemon : public FbsDaemonBase {
30  public:
31   ExynosDaemon();
~ExynosDaemon()32   ~ExynosDaemon() {
33     deinit();
34   }
35 
36   //! EXYNOS's shared memory size for CHRE <-> AP is 4KB.
37   static constexpr size_t kIpcMsgSizeMax = 4096;
38 
39   /**
40    * Initializes the CHRE daemon.
41    *
42    * @return true on successful init
43    */
44   bool init();
45 
46   /**
47    * Starts a socket server receive loop for inbound messages.
48    */
49   void run();
50 
51   void processIncomingMsgs();
52 
53   int64_t getTimeOffset(bool *success) override;
54 
55  protected:
56   void loadPreloadedNanoapp(const std::string &directory,
57                             const std::string &name,
58                             uint32_t transactionId) override;
59   void handleDaemonMessage(const uint8_t *message) override;
60   bool doSendMessage(void *data, size_t length) override;
61 
configureLpma(bool enabled)62   void configureLpma(bool enabled) override {
63     mLpmaHandler.enable(enabled);
64   }
65 
66  private:
67   static constexpr char kCommsDeviceFilename[] = "/dev/nanohub_comms";
68   static constexpr int kInvalidFd = -1;
69 
70   int mCommsReadFd = kInvalidFd;
71   int mCommsWriteFd = kInvalidFd;
72   std::thread mIncomingMsgProcessThread;
73   std::thread::native_handle_type mNativeThreadHandle;
74   std::atomic<bool> mProcessThreadRunning = false;
75 
76   StHalLpmaHandler mLpmaHandler;
77 
78   //! Set to the expected transaction, fragment, app ID for loading a nanoapp.
79   struct Transaction {
80     uint32_t transactionId;
81     uint32_t fragmentId;
82     uint64_t nanoappId;
83   };
84   Transaction mPreloadedNanoappPendingTransaction;
85 
86   //! The mutex used to guard state between the nanoapp messaging thread
87   //! and loading preloaded nanoapps.
88   std::mutex mPreloadedNanoappsMutex;
89 
90   //! The condition variable used to wait for a nanoapp to finish loading.
91   std::condition_variable mPreloadedNanoappsCond;
92 
93   //! Set to true when a preloaded nanoapp is pending load.
94   bool mPreloadedNanoappPending;
95 
96   /**
97    * Perform a graceful shutdown of the daemon
98    */
99   void deinit();
100 
101   /**
102    * Stops the inbound message processing thread (forcibly).
103    * Since the message read mechanism uses blocking system calls (poll, read),
104    * and since there's no timeout on the system calls (to avoid waking the AP
105    * up to handle timeouts), we forcibly terminate the thread on a daemon
106    * deinit. POSIX semantics are used since the C++20 threading interface does
107    * not provide an API to accomplish this.
108    */
109   void stopMsgProcessingThread();
110 
111   /**
112    * Sends a preloaded nanoapp to CHRE.
113    *
114    * @param header The nanoapp header binary blob.
115    * @param nanoapp The nanoapp binary blob.
116    * @param transactionId The transaction ID to use when loading the app.
117    * @return true if successful, false otherwise.
118    */
119   bool loadNanoapp(const std::vector<uint8_t> &header,
120                    const std::vector<uint8_t> &nanoapp, uint32_t transactionId);
121 
122   /**
123    * Loads a nanoapp using fragments.
124    *
125    * @param appId The ID of the nanoapp to load.
126    * @param appVersion The version of the nanoapp to load.
127    * @param appFlags The flags specified by the nanoapp to be loaded.
128    * @param appTargetApiVersion The version of the CHRE API that the app
129    * targets.
130    * @param appBinary The application binary code.
131    * @param appSize The size of the appBinary.
132    * @param transactionId The transaction ID to use when loading.
133    * @return true if successful, false otherwise.
134    */
135   bool sendFragmentedNanoappLoad(uint64_t appId, uint32_t appVersion,
136                                  uint32_t appFlags,
137                                  uint32_t appTargetApiVersion,
138                                  const uint8_t *appBinary, size_t appSize,
139                                  uint32_t transactionId);
140 
141   bool sendFragmentAndWaitOnResponse(uint32_t transactionId,
142                                      flatbuffers::FlatBufferBuilder &builder,
143                                      uint32_t fragmentId, uint64_t appId);
144 
145   /**
146    * Empty signal handler to handle SIGINT
147    */
signalHandler(int)148   static void signalHandler(int /*signal*/) {}
149 };
150 
151 }  // namespace chre
152 }  // namespace android
153 
154 #endif  // CHRE_EXYNOS_DAEMON_H_
155