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