blob: 0dceffee29447e6ae507308ac541399100bb5639 [file] [log] [blame]
/*
*
* Copyright 2021, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <android-base/logging.h>
#include <android/hardware/confirmationui/1.0/types.h>
#include <android/hardware/keymaster/4.0/types.h>
#include <condition_variable>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <tuple>
#include <vector>
#include "common/libs/concurrency/thread_safe_queue.h"
#include "common/libs/confui/confui.h"
#include "common/libs/fs/shared_fd.h"
namespace android {
namespace hardware {
namespace confirmationui {
namespace V1_0 {
namespace implementation {
class GuestSession {
public:
using ConfUiMessage = cuttlefish::confui::ConfUiMessage;
using ConfUiAckMessage = cuttlefish::confui::ConfUiAckMessage;
using Queue = cuttlefish::ThreadSafeQueue<std::unique_ptr<ConfUiMessage>>;
using QueueImpl = Queue::QueueImpl;
enum class ListenerState : uint32_t {
None = 0,
Starting = 1,
SetupDone = 2,
Interactive = 3,
Terminating = 4,
};
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)
: prompt_text_{promptText.begin(), promptText.end()}, extra_data_{extraData.begin(),
extraData.end()},
locale_{locale.begin(), locale.end()}, ui_options_{uiOptions.begin(), uiOptions.end()},
listener_state_(listener_state), listener_state_lock_(listener_state_lock),
listener_state_condv_(listener_state_condv), host_fd_{host_fd},
session_name_(MakeName(session_id)),
incoming_msg_queue_(
20, [this](GuestSession::QueueImpl* impl) { return QueueFullHandler(impl); }) {}
~GuestSession() {
// the thread for PromptUserConfirmation is still alive
// the host_fd_ may be alive
auto state = listener_state_;
if (state == ListenerState::SetupDone || state == ListenerState::Interactive) {
Abort();
}
// TODO(kwstephenkim): close fd once Session takes the ownership of fd
// join host_cmd_fetcher_thread_ once Session takes the ownership of fd
}
using ResultTriple =
std::tuple<ResponseCode, teeui::MsgVector<uint8_t>, teeui::MsgVector<uint8_t>>;
ResultTriple PromptUserConfirmation();
Return<ResponseCode> DeliverSecureInputEvent(
const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken);
Return<void> Abort();
std::string GetSessionId() const { return session_name_; }
void Push(std::unique_ptr<ConfUiMessage>&& msg) { incoming_msg_queue_.Push(std::move(msg)); }
private:
template <typename F, typename... Args>
bool SerializedSend(F&& f, cuttlefish::SharedFD fd, Args&&... args) {
if (!fd->IsOpen()) {
return false;
}
std::unique_lock<std::mutex> lock(send_serializer_mtx_);
return f(fd, std::forward<Args>(args)...);
}
void QueueFullHandler(QueueImpl* queue_impl) {
if (!queue_impl) {
LOG(ERROR) << "Registered queue handler is "
<< "seeing nullptr for queue implementation.";
return;
}
const auto n = (queue_impl->size()) / 2;
// pop front half
queue_impl->erase(queue_impl->begin(), queue_impl->begin() + n);
}
std::string MakeName(const std::uint32_t i) const {
return "ConfirmationUiSession" + std::to_string(i);
}
std::string prompt_text_;
std::vector<std::uint8_t> extra_data_;
std::string locale_;
std::vector<teeui::UIOption> ui_options_;
/*
* lister_state_lock_ coordinates multiple threads that may
* call the three Confirmation UI HAL APIs concurrently
*/
ListenerState& listener_state_;
std::mutex& listener_state_lock_;
std::condition_variable& listener_state_condv_;
cuttlefish::SharedFD host_fd_;
const std::string session_name_;
Queue incoming_msg_queue_;
/*
* multiple threads could try to write on the vsock at the
* same time. E.g. promptUserConfirmation() thread sends
* a command while abort() is being called. The abort() thread
* will try to write an abort command concurrently.
*/
std::mutex send_serializer_mtx_;
};
} // namespace implementation
} // namespace V1_0
} // namespace confirmationui
} // namespace hardware
} // namespace android