1 /* 2 * Copyright (C) 2021 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 #pragma once 18 19 #include <atomic> 20 #include <condition_variable> 21 #include <cstdint> 22 #include <functional> 23 #include <mutex> 24 25 #include <fruit/fruit.h> 26 27 #include "common/libs/confui/confui.h" 28 #include "host/libs/confui/host_utils.h" 29 30 namespace cuttlefish { 31 /** 32 * mechanism to orchestrate concurrent executions of threads 33 * that work for screen connector 34 * 35 * Within WebRTC service, it tells when it is now in the Android Mode or 36 * Confirmation UI mode 37 */ 38 class HostModeCtrl { 39 public: 40 enum class ModeType : std::uint8_t { kAndroidMode = 55, kConfUI_Mode = 77 }; INJECT(HostModeCtrl ())41 INJECT(HostModeCtrl()) : atomic_mode_(ModeType::kAndroidMode) {} 42 /** 43 * The thread that enqueues Android frames will call this to wait until 44 * the mode is kAndroidMode 45 * 46 * Logically, using atomic_mode_ alone is not sufficient. Using mutex alone 47 * is logically complete but slow. 48 * 49 * Note that most of the time, the mode is kAndroidMode. Also, note that 50 * this method is called at every single frame. 51 * 52 * As an optimization, we check atomic_mode_ first. If failed, we wait for 53 * kAndroidMode with mutex-based lock 54 * 55 * The actual synchronization is not at the and_mode_cv_.wait line but at 56 * this line: 57 * if (atomic_mode_ == ModeType::kAndroidMode) { 58 * 59 * This trick reduces the flag checking delays by 70+% on a Gentoo based 60 * amd64 desktop, with Linux 5.10 61 */ WaitAndroidMode()62 void WaitAndroidMode() { 63 ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName() 64 << "checking atomic Android mode"; 65 if (atomic_mode_ == ModeType::kAndroidMode) { 66 ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName() 67 << "returns as it is already Android mode"; 68 return; 69 } 70 auto check = [this]() -> bool { 71 return atomic_mode_ == ModeType::kAndroidMode; 72 }; 73 std::unique_lock<std::mutex> lock(mode_mtx_); 74 and_mode_cv_.wait(lock, check); 75 ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName() 76 << "awakes from cond var waiting for Android mode"; 77 } 78 SetMode(const ModeType mode)79 void SetMode(const ModeType mode) { 80 ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName() 81 << " tries to acquire the lock in SetMode"; 82 std::lock_guard<std::mutex> lock(mode_mtx_); 83 ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName() 84 << " acquired the lock in SetMode"; 85 atomic_mode_ = mode; 86 if (atomic_mode_ == ModeType::kAndroidMode) { 87 ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName() 88 << " signals kAndroidMode in SetMode"; 89 and_mode_cv_.notify_all(); 90 return; 91 } 92 ConfUiLog(DEBUG) << cuttlefish::confui::thread::GetName() 93 << "signals kConfUI_Mode in SetMode"; 94 confui_mode_cv_.notify_all(); 95 } 96 GetMode()97 auto GetMode() { 98 ModeType ret_val = atomic_mode_; 99 return ret_val; 100 } 101 IsConfirmatioUiMode()102 auto IsConfirmatioUiMode() { 103 return (atomic_mode_ == ModeType::kConfUI_Mode); 104 } 105 IsAndroidMode()106 auto IsAndroidMode() { return (atomic_mode_ == ModeType::kAndroidMode); } 107 Get()108 static HostModeCtrl& Get() { 109 static HostModeCtrl host_mode_controller; 110 return host_mode_controller; 111 } 112 113 private: 114 std::mutex mode_mtx_; 115 std::condition_variable and_mode_cv_; 116 std::condition_variable confui_mode_cv_; 117 std::atomic<ModeType> atomic_mode_; 118 }; 119 } // end of namespace cuttlefish 120