• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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[]>(kMaxPayloadBytes);
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   // TODO(b/277235389): Adjust max payload size (AP -> SCP and SCP -> AP)
108   // as appropriate. This is a temp/quick fix for b/272311907 and b/270758946
109   // setting max payload allowed to CHRE_MESSAGE_TO_HOST_MAX_SIZE + 128 byte
110   // to account for transport overhead.
111   static constexpr uint32_t kMaxPayloadBytes = 4224;  // 4096 + 128
112 
113   // Max overhead of the nanoapp binary payload caused by the fbs encapsulation
114   static constexpr uint32_t kMaxPayloadOverheadBytes = 1024;
115 
116   // The path to CHRE file descriptor
117   static constexpr char kChreFileDescriptorPath[] = "/dev/scp_chre_manager";
118 
119   // Max queue size for sending messages to CHRE
120   static constexpr size_t kMaxSynchronousMessageQueueSize = 64;
121 
122   // Wrapper for a message sent to CHRE
123   struct ChreConnectionMessage {
124     // This magic number is the SCP_CHRE_MAGIC constant defined by kernel
125     // scp_chre_manager service. The value is embedded in the payload as a
126     // security check for proper use of the device node.
127     uint32_t magic = 0x67728269;
128     uint32_t payloadSize = 0;
129     uint8_t payload[kMaxPayloadBytes];
130 
ChreConnectionMessageChreConnectionMessage131     ChreConnectionMessage(void *data, size_t length) {
132       assert(length <= kMaxPayloadBytes);
133       memcpy(payload, data, length);
134       payloadSize = static_cast<uint32_t>(length);
135     }
136 
getMessageSizeChreConnectionMessage137     uint32_t getMessageSize() {
138       return sizeof(magic) + sizeof(payloadSize) + payloadSize;
139     }
140   };
141 
142   // A queue suitable for multiple producers and a single consumer.
143   class SynchronousMessageQueue {
144    public:
emplace(void * data,size_t length)145     bool emplace(void *data, size_t length) {
146       std::unique_lock<std::mutex> lock(mMutex);
147       if (mQueue.size() >= kMaxSynchronousMessageQueueSize) {
148         LOGE("Message queue from HAL to CHRE is full!");
149         return false;
150       }
151       mQueue.emplace(data, length);
152       mCv.notify_all();
153       return true;
154     }
155 
pop()156     void pop() {
157       std::unique_lock<std::mutex> lock(mMutex);
158       mQueue.pop();
159     }
160 
front()161     ChreConnectionMessage &front() {
162       std::unique_lock<std::mutex> lock(mMutex);
163       return mQueue.front();
164     }
165 
waitForMessage()166     void waitForMessage() {
167       std::unique_lock<std::mutex> lock(mMutex);
168       mCv.wait(lock, [&]() { return !mQueue.empty(); });
169     }
170 
171    private:
172     std::mutex mMutex;
173     std::condition_variable mCv;
174     std::queue<ChreConnectionMessage> mQueue;
175   };
176 
177   // The task receiving message from CHRE
178   [[noreturn]] static void messageListenerTask(
179       TinysysChreConnection *chreConnection);
180 
181   // The task sending message to CHRE
182   [[noreturn]] static void messageSenderTask(
183       TinysysChreConnection *chreConnection);
184 
185   // The task receiving CHRE state update
186   [[noreturn]] static void chreStateMonitorTask(
187       TinysysChreConnection *chreConnection);
188 
getChreFileDescriptor()189   [[nodiscard]] inline int getChreFileDescriptor() const {
190     return mChreFileDescriptor;
191   }
192 
193   // The file descriptor for communication with CHRE
194   int mChreFileDescriptor;
195 
196   // The calback function that should be implemented by HAL
197   ChreConnectionCallback *mCallback;
198 
199   // the message listener thread that receives messages from CHRE
200   std::thread mMessageListener;
201   // the message sender thread that sends messages to CHRE
202   std::thread mMessageSender;
203   // the status listener thread that hosts chreStateMonitorTask
204   std::thread mStateListener;
205 
206   // Payload received from CHRE
207   std::unique_ptr<uint8_t[]> mPayload;
208 
209   // The LPMA handler to talk to the ST HAL
210   StHalLpmaHandler mLpmaHandler;
211 
212   // For messages sent to CHRE
213   SynchronousMessageQueue mQueue;
214 
215   // Mutex and CV are used to get PulseResponse from CHRE synchronously.
216   std::mutex mChrePulseMutex;
217   std::condition_variable mChrePulseCondition;
218   bool mIsChreBackOnline =
219       false;  // set to true after CHRE recovers from a restart
220 };
221 }  // namespace aidl::android::hardware::contexthub
222 
223 #endif  // TINYSYS_CHRE_CONNECTION_H_
224