xref: /aosp_15_r20/system/chre/host/tinysys/hal/tinysys_chre_connection.h (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2023 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 TINYSYS_CHRE_CONNECTION_H_
18 #define TINYSYS_CHRE_CONNECTION_H_
19 
20 #include "chre_connection.h"
21 #include "chre_connection_callback.h"
22 #include "chre_host/fragmented_load_transaction.h"
23 #include "chre_host/host_protocol_host.h"
24 #include "chre_host/log.h"
25 #include "chre_host/log_message_parser.h"
26 #include "chre_host/st_hal_lpma_handler.h"
27 
28 #include <unistd.h>
29 #include <cassert>
30 #include <future>
31 #include <queue>
32 #include <thread>
33 
34 using ::android::chre::StHalLpmaHandler;
35 
36 namespace aidl::android::hardware::contexthub {
37 
38 using namespace ::android::hardware::contexthub::common::implementation;
39 using ::android::chre::HostProtocolHost;
40 
41 /** A class handling message transmission between context hub HAL and CHRE. */
42 // TODO(b/267188769): We should add comments explaining how IPI works.
43 class TinysysChreConnection : public ChreConnection {
44  public:
TinysysChreConnection(ChreConnectionCallback * callback)45   TinysysChreConnection(ChreConnectionCallback *callback)
46       : mCallback(callback), mLpmaHandler(/* allowed= */ true) {
47     mPayload = std::make_unique<uint8_t[]>(kMaxReceivingPayloadBytes);
48   };
49 
~TinysysChreConnection()50   ~TinysysChreConnection() override {
51     // TODO(b/264308286): Need a decent way to terminate the listener thread.
52     close(mChreFileDescriptor);
53     if (mMessageListener.joinable()) {
54       mMessageListener.join();
55     }
56     if (mMessageSender.joinable()) {
57       mMessageSender.join();
58     }
59     if (mStateListener.joinable()) {
60       mStateListener.join();
61     }
62   }
63 
64   static void handleMessageFromChre(TinysysChreConnection *chreConnection,
65                                     const unsigned char *messageBuffer,
66                                     size_t messageLen);
67 
68   bool init() override;
69 
70   bool sendMessage(void *data, size_t length) override;
71 
waitChreBackOnline(std::chrono::milliseconds timeoutMs)72   void waitChreBackOnline(std::chrono::milliseconds timeoutMs) {
73     flatbuffers::FlatBufferBuilder builder(48);
74     HostProtocolHost::encodePulseRequest(builder);
75 
76     std::unique_lock<std::mutex> lock(mChrePulseMutex);
77     // reset mIsChreRecovered before sending a PulseRequest message
78     mIsChreBackOnline = false;
79     sendMessage(builder.GetBufferPointer(), builder.GetSize());
80     mChrePulseCondition.wait_for(
81         lock, timeoutMs,
82         [&isChreBackOnline = mIsChreBackOnline] { return isChreBackOnline; });
83   }
84 
notifyChreBackOnline()85   void notifyChreBackOnline() {
86     {
87       std::unique_lock<std::mutex> lock(mChrePulseMutex);
88       mIsChreBackOnline = true;
89     }
90     mChrePulseCondition.notify_all();
91   }
92 
getCallback()93   inline ChreConnectionCallback *getCallback() {
94     return mCallback;
95   }
96 
getLpmaHandler()97   inline StHalLpmaHandler *getLpmaHandler() {
98     return &mLpmaHandler;
99   }
100 
101  private:
102   // The wakelock used to keep device awake while handleUsfMsgAsync() is being
103   // called.
104   static constexpr char kWakeLock[] = "tinysys_chre_hal_wakelock";
105 
106   // Max payload size that can be sent to CHRE
107   static constexpr uint32_t kMaxSendingPayloadBytes = 0x8000;  // 32K
108 
109   // Max payload size that can be received from CHRE
110   static constexpr uint32_t kMaxReceivingPayloadBytes = 0x8000;  // 32K
111 
112   // Max overhead of the nanoapp binary payload caused by the fbs encapsulation
113   static constexpr uint32_t kMaxPayloadOverheadBytes = 1024;
114 
115   // The path to CHRE file descriptor
116   static constexpr char kChreFileDescriptorPath[] = "/dev/scp_chre_manager";
117 
118   // Max queue size for sending messages to CHRE
119   static constexpr size_t kMaxSynchronousMessageQueueSize = 64;
120 
121   // Wrapper for a message sent to CHRE
122   struct ChreConnectionMessage {
123     // This magic number is the SCP_CHRE_MAGIC constant defined by kernel
124     // scp_chre_manager service. The value is embedded in the payload as a
125     // security check for proper use of the device node.
126     uint32_t magic = 0x67728269;
127     uint32_t payloadSize = 0;
128     uint8_t payload[kMaxSendingPayloadBytes];
129 
ChreConnectionMessageChreConnectionMessage130     ChreConnectionMessage(void *data, size_t length) {
131       assert(length <= kMaxSendingPayloadBytes);
132       memcpy(payload, data, length);
133       payloadSize = static_cast<uint32_t>(length);
134     }
135 
getMessageSizeChreConnectionMessage136     uint32_t getMessageSize() {
137       return sizeof(magic) + sizeof(payloadSize) + payloadSize;
138     }
139   };
140 
141   // A queue suitable for multiple producers and a single consumer.
142   class SynchronousMessageQueue {
143    public:
emplace(void * data,size_t length)144     bool emplace(void *data, size_t length) {
145       std::unique_lock<std::mutex> lock(mMutex);
146       if (mQueue.size() >= kMaxSynchronousMessageQueueSize) {
147         LOGE("Message queue from HAL to CHRE is full!");
148         return false;
149       }
150       mQueue.emplace(data, length);
151       mCv.notify_all();
152       return true;
153     }
154 
pop()155     void pop() {
156       std::unique_lock<std::mutex> lock(mMutex);
157       mQueue.pop();
158     }
159 
front()160     ChreConnectionMessage &front() {
161       std::unique_lock<std::mutex> lock(mMutex);
162       return mQueue.front();
163     }
164 
waitForMessage()165     void waitForMessage() {
166       std::unique_lock<std::mutex> lock(mMutex);
167       mCv.wait(lock, [&]() { return !mQueue.empty(); });
168     }
169 
170    private:
171     std::mutex mMutex;
172     std::condition_variable mCv;
173     std::queue<ChreConnectionMessage> mQueue;
174   };
175 
176   // The task receiving message from CHRE
177   [[noreturn]] static void messageListenerTask(
178       TinysysChreConnection *chreConnection);
179 
180   // The task sending message to CHRE
181   [[noreturn]] static void messageSenderTask(
182       TinysysChreConnection *chreConnection);
183 
184   // The task receiving CHRE state update
185   [[noreturn]] static void chreStateMonitorTask(
186       TinysysChreConnection *chreConnection);
187 
getChreFileDescriptor()188   [[nodiscard]] inline int getChreFileDescriptor() const {
189     return mChreFileDescriptor;
190   }
191 
192   // The file descriptor for communication with CHRE
193   int mChreFileDescriptor;
194 
195   // The calback function that should be implemented by HAL
196   ChreConnectionCallback *mCallback;
197 
198   // the message listener thread that receives messages from CHRE
199   std::thread mMessageListener;
200   // the message sender thread that sends messages to CHRE
201   std::thread mMessageSender;
202   // the status listener thread that hosts chreStateMonitorTask
203   std::thread mStateListener;
204 
205   // Payload received from CHRE
206   std::unique_ptr<uint8_t[]> mPayload;
207 
208   // The LPMA handler to talk to the ST HAL
209   StHalLpmaHandler mLpmaHandler;
210 
211   // For messages sent to CHRE
212   SynchronousMessageQueue mQueue;
213 
214   // Mutex and CV are used to get PulseResponse from CHRE synchronously.
215   std::mutex mChrePulseMutex;
216   std::condition_variable mChrePulseCondition;
217   bool mIsChreBackOnline =
218       false;  // set to true after CHRE recovers from a restart
219 };
220 }  // namespace aidl::android::hardware::contexthub
221 
222 #endif  // TINYSYS_CHRE_CONNECTION_H_
223