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