• 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/log.h"
24 #include "chre_host/log_message_parser.h"
25 #include "chre_host/st_hal_lpma_handler.h"
26 
27 #include <unistd.h>
28 #include <cassert>
29 #include <future>
30 #include <queue>
31 #include <thread>
32 
33 using ::android::chre::StHalLpmaHandler;
34 
35 namespace aidl::android::hardware::contexthub {
36 
37 using namespace ::android::hardware::contexthub::common::implementation;
38 
39 /** A class handling message transmission between context hub HAL and CHRE. */
40 // TODO(b/267188769): We should add comments explaining how IPI works.
41 class TinysysChreConnection : public ChreConnection {
42  public:
TinysysChreConnection(ChreConnectionCallback * callback)43   TinysysChreConnection(ChreConnectionCallback *callback)
44       : mCallback(callback), mLpmaHandler(/* allowed= */ true) {
45     mPayload = std::make_unique<uint8_t[]>(kMaxPayloadBytes);
46   };
47 
~TinysysChreConnection()48   ~TinysysChreConnection() override {
49     // TODO(b/264308286): Need a decent way to terminate the listener thread.
50     close(mChreFileDescriptor);
51     if (mMessageListener.joinable()) {
52       mMessageListener.join();
53     }
54     if (mMessageSender.joinable()) {
55       mMessageSender.join();
56     }
57     if (mStateListener.joinable()) {
58       mStateListener.join();
59     }
60   }
61 
62   static void handleMessageFromChre(TinysysChreConnection *chreConnection,
63                                     const unsigned char *messageBuffer,
64                                     size_t messageLen);
65 
66   bool init() override;
67 
68   bool sendMessage(void *data, size_t length) override;
69 
getCallback()70   inline ChreConnectionCallback *getCallback() {
71     return mCallback;
72   }
73 
getLpmaHandler()74   inline StHalLpmaHandler *getLpmaHandler() {
75     return &mLpmaHandler;
76   }
77 
78  private:
79   // The wakelock used to keep device awake while handleUsfMsgAsync() is being
80   // called.
81   static constexpr char kWakeLock[] = "tinysys_chre_hal_wakelock";
82 
83   // Max payload size that can be sent to CHRE
84   // TODO(b/277235389): Adjust max payload size (AP -> SCP and SCP -> AP)
85   // as appropriate. This is a temp/quick fix for b/272311907 and b/270758946
86   // setting max payload allowed to CHRE_MESSAGE_TO_HOST_MAX_SIZE + 128 byte
87   // to account for transport overhead.
88   static constexpr uint32_t kMaxPayloadBytes = 4224;  // 4096 + 128
89 
90   // Max overhead of the nanoapp binary payload caused by the fbs encapsulation
91   static constexpr uint32_t kMaxPayloadOverheadBytes = 1024;
92 
93   // The path to CHRE file descriptor
94   static constexpr char kChreFileDescriptorPath[] = "/dev/scp_chre_manager";
95 
96   // Max queue size for sending messages to CHRE
97   static constexpr size_t kMaxSynchronousMessageQueueSize = 64;
98 
99   // Wrapper for a message sent to CHRE
100   struct ChreConnectionMessage {
101     // This magic number is the SCP_CHRE_MAGIC constant defined by kernel
102     // scp_chre_manager service. The value is embedded in the payload as a
103     // security check for proper use of the device node.
104     uint32_t magic = 0x67728269;
105     uint32_t payloadSize = 0;
106     uint8_t payload[kMaxPayloadBytes];
107 
ChreConnectionMessageChreConnectionMessage108     ChreConnectionMessage(void *data, size_t length) {
109       assert(length <= kMaxPayloadBytes);
110       memcpy(payload, data, length);
111       payloadSize = static_cast<uint32_t>(length);
112     }
113 
getMessageSizeChreConnectionMessage114     uint32_t getMessageSize() {
115       return sizeof(magic) + sizeof(payloadSize) + payloadSize;
116     }
117   };
118 
119   // A queue suitable for multiple producers and a single consumer.
120   class SynchronousMessageQueue {
121    public:
emplace(void * data,size_t length)122     bool emplace(void *data, size_t length) {
123       std::unique_lock<std::mutex> lock(mMutex);
124       if (mQueue.size() >= kMaxSynchronousMessageQueueSize) {
125         LOGE("Message queue from HAL to CHRE is full!");
126         return false;
127       }
128       mQueue.emplace(data, length);
129       mCv.notify_all();
130       return true;
131     }
132 
pop()133     void pop() {
134       std::unique_lock<std::mutex> lock(mMutex);
135       mQueue.pop();
136     }
137 
front()138     ChreConnectionMessage &front() {
139       std::unique_lock<std::mutex> lock(mMutex);
140       return mQueue.front();
141     }
142 
waitForMessage()143     void waitForMessage() {
144       std::unique_lock<std::mutex> lock(mMutex);
145       mCv.wait(lock, [&]() { return !mQueue.empty(); });
146     }
147 
148    private:
149     std::mutex mMutex;
150     std::condition_variable mCv;
151     std::queue<ChreConnectionMessage> mQueue;
152   };
153 
154   // The task receiving message from CHRE
155   [[noreturn]] static void messageListenerTask(
156       TinysysChreConnection *chreConnection);
157 
158   // The task sending message to CHRE
159   [[noreturn]] static void messageSenderTask(
160       TinysysChreConnection *chreConnection);
161 
162   // The task receiving CHRE state update
163   [[noreturn]] static void chreStateMonitorTask(
164       TinysysChreConnection *chreConnection);
165 
getChreFileDescriptor()166   [[nodiscard]] inline int getChreFileDescriptor() const {
167     return mChreFileDescriptor;
168   }
169 
170   // The parser of buffered logs from CHRE
171   ::android::chre::LogMessageParser mLogger{};
172 
173   // The file descriptor for communication with CHRE
174   int mChreFileDescriptor;
175 
176   // The calback function that should be implemented by HAL
177   ChreConnectionCallback *mCallback;
178 
179   // the message listener thread that receives messages from CHRE
180   std::thread mMessageListener;
181   // the message sender thread that sends messages to CHRE
182   std::thread mMessageSender;
183   // the status listener thread that hosts chreStateMonitorTask
184   std::thread mStateListener;
185 
186   // Payload received from CHRE
187   std::unique_ptr<uint8_t[]> mPayload;
188 
189   // The LPMA handler to talk to the ST HAL
190   StHalLpmaHandler mLpmaHandler;
191 
192   // For messages sent to CHRE
193   SynchronousMessageQueue mQueue;
194 };
195 }  // namespace aidl::android::hardware::contexthub
196 
197 #endif  // TINYSYS_CHRE_CONNECTION_H_
198