peripheral_notification_manager.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/components/peripheral_notification/peripheral_notification_manager.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "base/callback_helpers.h"
  7. #include "base/files/file_path.h"
  8. #include "base/files/file_util.h"
  9. #include "base/metrics/histogram_functions.h"
  10. #include "base/task/task_traits.h"
  11. #include "base/task/thread_pool.h"
  12. #include "services/device/public/mojom/usb_device.mojom.h"
  13. #include "third_party/cros_system_api/dbus/typecd/dbus-constants.h"
  14. namespace ash {
  15. namespace {
  16. PeripheralNotificationManager* g_instance = nullptr;
  17. const int kBillboardDeviceClassCode = 17;
  18. constexpr char thunderbolt_file_path[] = "/sys/bus/thunderbolt/devices/0-0";
  19. void RecordConnectivityMetric(
  20. PeripheralNotificationManager::PeripheralConnectivityResults results) {
  21. base::UmaHistogramEnumeration("Ash.Peripheral.ConnectivityResults", results);
  22. }
  23. // Checks if the board supports Thunderbolt.
  24. bool CheckIfThunderboltFilepathExists(std::string root_prefix) {
  25. return base::PathExists(base::FilePath(root_prefix + thunderbolt_file_path));
  26. }
  27. } // namespace
  28. PeripheralNotificationManager::PeripheralNotificationManager(
  29. bool is_guest_profile,
  30. bool is_pcie_tunneling_allowed)
  31. : is_guest_profile_(is_guest_profile),
  32. is_pcie_tunneling_allowed_(is_pcie_tunneling_allowed) {
  33. DCHECK(TypecdClient::Get());
  34. DCHECK(PciguardClient::Get());
  35. TypecdClient::Get()->AddObserver(this);
  36. PciguardClient::Get()->AddObserver(this);
  37. }
  38. PeripheralNotificationManager::~PeripheralNotificationManager() {
  39. TypecdClient::Get()->RemoveObserver(this);
  40. PciguardClient::Get()->RemoveObserver(this);
  41. CHECK_EQ(this, g_instance);
  42. g_instance = nullptr;
  43. }
  44. void PeripheralNotificationManager::AddObserver(Observer* observer) {
  45. observer_list_.AddObserver(observer);
  46. }
  47. void PeripheralNotificationManager::RemoveObserver(Observer* observer) {
  48. observer_list_.RemoveObserver(observer);
  49. }
  50. void PeripheralNotificationManager::
  51. NotifyLimitedPerformancePeripheralReceived() {
  52. // Show no notifications if PCIe tunneling is allowed.
  53. if (is_pcie_tunneling_allowed_)
  54. return;
  55. for (auto& observer : observer_list_)
  56. observer.OnLimitedPerformancePeripheralReceived();
  57. }
  58. void PeripheralNotificationManager::NotifyGuestModeNotificationReceived(
  59. bool is_thunderbolt_only) {
  60. for (auto& observer : observer_list_)
  61. observer.OnGuestModeNotificationReceived(is_thunderbolt_only);
  62. }
  63. void PeripheralNotificationManager::NotifyPeripheralBlockedReceived() {
  64. for (auto& observer : observer_list_)
  65. observer.OnPeripheralBlockedReceived();
  66. }
  67. void PeripheralNotificationManager::OnBillboardDeviceConnected(
  68. bool billboard_is_supported) {
  69. if (!features::IsPcieBillboardNotificationEnabled()) {
  70. return;
  71. }
  72. if (!billboard_is_supported) {
  73. for (auto& observer : observer_list_)
  74. observer.OnBillboardDeviceConnected();
  75. RecordConnectivityMetric(PeripheralConnectivityResults::kBillboardDevice);
  76. }
  77. }
  78. void PeripheralNotificationManager::OnThunderboltDeviceConnected(
  79. bool is_thunderbolt_only) {
  80. if (is_guest_profile_) {
  81. NotifyGuestModeNotificationReceived(is_thunderbolt_only);
  82. RecordConnectivityMetric(
  83. is_thunderbolt_only
  84. ? PeripheralConnectivityResults::kTBTOnlyAndBlockedInGuestSession
  85. : PeripheralConnectivityResults::kAltModeFallbackInGuestSession);
  86. return;
  87. }
  88. // Only show notifications if the peripheral is operating at limited
  89. // performance.
  90. if (!is_pcie_tunneling_allowed_) {
  91. NotifyLimitedPerformancePeripheralReceived();
  92. RecordConnectivityMetric(
  93. is_thunderbolt_only
  94. ? PeripheralConnectivityResults::kTBTOnlyAndBlockedByPciguard
  95. : PeripheralConnectivityResults::kAltModeFallbackDueToPciguard);
  96. return;
  97. }
  98. RecordConnectivityMetric(
  99. PeripheralConnectivityResults::kTBTSupportedAndAllowed);
  100. }
  101. void PeripheralNotificationManager::OnBlockedThunderboltDeviceConnected(
  102. const std::string& name) {
  103. // Currently the device name is not shown in the notification.
  104. NotifyPeripheralBlockedReceived();
  105. RecordConnectivityMetric(PeripheralConnectivityResults::kPeripheralBlocked);
  106. }
  107. void PeripheralNotificationManager::OnCableWarning(
  108. typecd::CableWarningType cable_warning_type) {
  109. // Decode cable warnging signal.
  110. switch (cable_warning_type) {
  111. case typecd::CableWarningType::kInvalidDpCable:
  112. NotifyInvalidDpCable();
  113. RecordConnectivityMetric(PeripheralConnectivityResults::kInvalidDpCable);
  114. break;
  115. case typecd::CableWarningType::kInvalidUSB4ValidTBTCable:
  116. NotifyInvalidUSB4ValidTBTCableWarning();
  117. RecordConnectivityMetric(
  118. PeripheralConnectivityResults::kInvalidUSB4ValidTBTCable);
  119. break;
  120. case typecd::CableWarningType::kInvalidUSB4Cable:
  121. NotifyInvalidUSB4CableWarning();
  122. RecordConnectivityMetric(
  123. PeripheralConnectivityResults::kInvalidUSB4Cable);
  124. break;
  125. case typecd::CableWarningType::kInvalidTBTCable:
  126. NotifyInvalidTBTCableWarning();
  127. RecordConnectivityMetric(PeripheralConnectivityResults::kInvalidTBTCable);
  128. break;
  129. case typecd::CableWarningType::kSpeedLimitingCable:
  130. NotifySpeedLimitingCableWarning();
  131. RecordConnectivityMetric(
  132. PeripheralConnectivityResults::kSpeedLimitingCable);
  133. break;
  134. default:
  135. break;
  136. }
  137. }
  138. void PeripheralNotificationManager::NotifyInvalidDpCable() {
  139. for (auto& observer : observer_list_)
  140. observer.OnInvalidDpCableWarning();
  141. }
  142. void PeripheralNotificationManager::NotifyInvalidUSB4ValidTBTCableWarning() {
  143. for (auto& observer : observer_list_)
  144. observer.OnInvalidUSB4ValidTBTCableWarning();
  145. }
  146. void PeripheralNotificationManager::NotifyInvalidUSB4CableWarning() {
  147. for (auto& observer : observer_list_)
  148. observer.OnInvalidUSB4CableWarning();
  149. }
  150. void PeripheralNotificationManager::NotifyInvalidTBTCableWarning() {
  151. for (auto& observer : observer_list_)
  152. observer.OnInvalidTBTCableWarning();
  153. }
  154. void PeripheralNotificationManager::NotifySpeedLimitingCableWarning() {
  155. for (auto& observer : observer_list_)
  156. observer.OnSpeedLimitingCableWarning();
  157. }
  158. void PeripheralNotificationManager::OnDeviceConnected(
  159. device::mojom::UsbDeviceInfo* device) {
  160. if (device->class_code == kBillboardDeviceClassCode) {
  161. // PathExist is a blocking call. PostTask it and wait on the result.
  162. base::ThreadPool::PostTaskAndReplyWithResult(
  163. FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
  164. base::BindOnce(&CheckIfThunderboltFilepathExists, root_prefix_),
  165. base::BindOnce(
  166. &PeripheralNotificationManager::OnBillboardDeviceConnected,
  167. weak_ptr_factory_.GetWeakPtr()));
  168. }
  169. }
  170. void PeripheralNotificationManager::SetPcieTunnelingAllowedState(
  171. bool is_pcie_tunneling_allowed) {
  172. is_pcie_tunneling_allowed_ = is_pcie_tunneling_allowed;
  173. }
  174. void PeripheralNotificationManager::SetRootPrefixForTesting(
  175. const std::string& prefix) {
  176. root_prefix_ = prefix;
  177. }
  178. // static
  179. void PeripheralNotificationManager::Initialize(bool is_guest_profile,
  180. bool is_pcie_tunneling_allowed) {
  181. CHECK(!g_instance);
  182. g_instance = new PeripheralNotificationManager(is_guest_profile,
  183. is_pcie_tunneling_allowed);
  184. }
  185. // static
  186. void PeripheralNotificationManager::Shutdown() {
  187. CHECK(g_instance);
  188. delete g_instance;
  189. g_instance = NULL;
  190. }
  191. // static
  192. PeripheralNotificationManager* PeripheralNotificationManager::Get() {
  193. CHECK(g_instance);
  194. return g_instance;
  195. }
  196. // static
  197. bool PeripheralNotificationManager::IsInitialized() {
  198. return g_instance;
  199. }
  200. } // namespace ash