1 /* 2 * 3 * Copyright 2021, The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #pragma once 19 20 #include <android-base/logging.h> 21 #include <android/hardware/confirmationui/1.0/types.h> 22 #include <android/hardware/keymaster/4.0/types.h> 23 24 #include <condition_variable> 25 #include <cstdint> 26 #include <memory> 27 #include <mutex> 28 #include <string> 29 #include <tuple> 30 #include <vector> 31 32 #include "common/libs/concurrency/thread_safe_queue.h" 33 #include "common/libs/confui/confui.h" 34 #include "common/libs/fs/shared_fd.h" 35 36 namespace android { 37 namespace hardware { 38 namespace confirmationui { 39 namespace V1_0 { 40 namespace implementation { 41 class GuestSession { 42 public: 43 using ConfUiMessage = cuttlefish::confui::ConfUiMessage; 44 using ConfUiAckMessage = cuttlefish::confui::ConfUiAckMessage; 45 using Queue = cuttlefish::ThreadSafeQueue<std::unique_ptr<ConfUiMessage>>; 46 using QueueImpl = Queue::QueueImpl; 47 48 enum class ListenerState : uint32_t { 49 None = 0, 50 Starting = 1, 51 SetupDone = 2, 52 Interactive = 3, 53 Terminating = 4, 54 }; 55 GuestSession(const std::uint32_t session_id,ListenerState & listener_state,std::mutex & listener_state_lock,std::condition_variable & listener_state_condv,cuttlefish::SharedFD host_fd,const teeui::MsgString & promptText,const teeui::MsgVector<uint8_t> & extraData,const teeui::MsgString & locale,const teeui::MsgVector<teeui::UIOption> & uiOptions)56 GuestSession(const std::uint32_t session_id, ListenerState& listener_state, 57 std::mutex& listener_state_lock, std::condition_variable& listener_state_condv, 58 cuttlefish::SharedFD host_fd, const teeui::MsgString& promptText, 59 const teeui::MsgVector<uint8_t>& extraData, const teeui::MsgString& locale, 60 const teeui::MsgVector<teeui::UIOption>& uiOptions) 61 : prompt_text_{promptText.begin(), promptText.end()}, extra_data_{extraData.begin(), 62 extraData.end()}, 63 locale_{locale.begin(), locale.end()}, ui_options_{uiOptions.begin(), uiOptions.end()}, 64 listener_state_(listener_state), listener_state_lock_(listener_state_lock), 65 listener_state_condv_(listener_state_condv), host_fd_{host_fd}, 66 session_name_(MakeName(session_id)), 67 incoming_msg_queue_( 68 20, [this](GuestSession::QueueImpl* impl) { return QueueFullHandler(impl); }) {} 69 ~GuestSession()70 ~GuestSession() { 71 // the thread for PromptUserConfirmation is still alive 72 // the host_fd_ may be alive 73 auto state = listener_state_; 74 if (state == ListenerState::SetupDone || state == ListenerState::Interactive) { 75 Abort(); 76 } 77 // TODO(kwstephenkim): close fd once Session takes the ownership of fd 78 // join host_cmd_fetcher_thread_ once Session takes the ownership of fd 79 } 80 81 using ResultTriple = 82 std::tuple<ResponseCode, teeui::MsgVector<uint8_t>, teeui::MsgVector<uint8_t>>; 83 ResultTriple PromptUserConfirmation(); 84 85 Return<ResponseCode> DeliverSecureInputEvent( 86 const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken); 87 88 Return<void> Abort(); GetSessionId()89 std::string GetSessionId() const { return session_name_; } 90 Push(std::unique_ptr<ConfUiMessage> && msg)91 void Push(std::unique_ptr<ConfUiMessage>&& msg) { incoming_msg_queue_.Push(std::move(msg)); } 92 93 private: 94 template <typename F, typename... Args> SerializedSend(F && f,cuttlefish::SharedFD fd,Args &&...args)95 bool SerializedSend(F&& f, cuttlefish::SharedFD fd, Args&&... args) { 96 if (!fd->IsOpen()) { 97 return false; 98 } 99 std::unique_lock<std::mutex> lock(send_serializer_mtx_); 100 return f(fd, std::forward<Args>(args)...); 101 } 102 QueueFullHandler(QueueImpl * queue_impl)103 void QueueFullHandler(QueueImpl* queue_impl) { 104 if (!queue_impl) { 105 LOG(ERROR) << "Registered queue handler is " 106 << "seeing nullptr for queue implementation."; 107 return; 108 } 109 const auto n = (queue_impl->size()) / 2; 110 // pop front half 111 queue_impl->erase(queue_impl->begin(), queue_impl->begin() + n); 112 } 113 MakeName(const std::uint32_t i)114 std::string MakeName(const std::uint32_t i) const { 115 return "ConfirmationUiSession" + std::to_string(i); 116 } 117 std::string prompt_text_; 118 std::vector<std::uint8_t> extra_data_; 119 std::string locale_; 120 std::vector<teeui::UIOption> ui_options_; 121 122 /* 123 * lister_state_lock_ coordinates multiple threads that may 124 * call the three Confirmation UI HAL APIs concurrently 125 */ 126 ListenerState& listener_state_; 127 std::mutex& listener_state_lock_; 128 std::condition_variable& listener_state_condv_; 129 cuttlefish::SharedFD host_fd_; 130 131 const std::string session_name_; 132 Queue incoming_msg_queue_; 133 134 /* 135 * multiple threads could try to write on the vsock at the 136 * same time. E.g. promptUserConfirmation() thread sends 137 * a command while abort() is being called. The abort() thread 138 * will try to write an abort command concurrently. 139 */ 140 std::mutex send_serializer_mtx_; 141 }; 142 } // namespace implementation 143 } // namespace V1_0 144 } // namespace confirmationui 145 } // namespace hardware 146 } // namespace android 147