arc_intent_helper_bridge.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // Copyright 2016 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 "components/arc/intent_helper/arc_intent_helper_bridge.h"
  5. #include <iterator>
  6. #include <utility>
  7. #include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
  8. #include "ash/components/arc/audio/arc_audio_bridge.h"
  9. #include "ash/components/arc/session/arc_bridge_service.h"
  10. #include "ash/components/arc/session/arc_service_manager.h"
  11. #include "ash/public/cpp/new_window_delegate.h"
  12. #include "ash/public/cpp/system/power/power_button_controller_base.h"
  13. #include "ash/public/cpp/wallpaper/wallpaper_controller.h"
  14. #include "base/json/json_writer.h"
  15. #include "base/logging.h"
  16. #include "base/memory/singleton.h"
  17. #include "base/memory/weak_ptr.h"
  18. #include "base/metrics/histogram_macros.h"
  19. #include "base/strings/string_util.h"
  20. #include "base/values.h"
  21. #include "components/arc/common/intent_helper/arc_intent_helper_package.h"
  22. #include "components/arc/intent_helper/control_camera_app_delegate.h"
  23. #include "components/arc/intent_helper/intent_constants.h"
  24. #include "components/arc/intent_helper/open_url_delegate.h"
  25. #include "components/url_formatter/url_fixer.h"
  26. #include "net/base/url_util.h"
  27. #include "third_party/abseil-cpp/absl/types/optional.h"
  28. #include "ui/base/layout.h"
  29. #include "url/url_constants.h"
  30. namespace arc {
  31. namespace {
  32. constexpr const char* kArcSchemes[] = {url::kHttpScheme, url::kHttpsScheme,
  33. url::kContentScheme, url::kFileScheme,
  34. url::kMailToScheme};
  35. // Not owned. Must outlive all ArcIntentHelperBridge instances. Typically this
  36. // is ChromeNewWindowClient in the browser.
  37. OpenUrlDelegate* g_open_url_delegate = nullptr;
  38. ControlCameraAppDelegate* g_control_camera_app_delegate = nullptr;
  39. // Singleton factory for ArcIntentHelperBridge.
  40. class ArcIntentHelperBridgeFactory
  41. : public internal::ArcBrowserContextKeyedServiceFactoryBase<
  42. ArcIntentHelperBridge,
  43. ArcIntentHelperBridgeFactory> {
  44. public:
  45. // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
  46. static constexpr const char* kName = "ArcIntentHelperBridgeFactory";
  47. static ArcIntentHelperBridgeFactory* GetInstance() {
  48. return base::Singleton<ArcIntentHelperBridgeFactory>::get();
  49. }
  50. private:
  51. friend struct base::DefaultSingletonTraits<ArcIntentHelperBridgeFactory>;
  52. ArcIntentHelperBridgeFactory() = default;
  53. ~ArcIntentHelperBridgeFactory() override = default;
  54. };
  55. // Keep in sync with ArcIntentHelperOpenType enum in
  56. // //tools/metrics/histograms/enums.xml.
  57. enum class ArcIntentHelperOpenType {
  58. DOWNLOADS = 0,
  59. URL = 1,
  60. CUSTOM_TAB = 2,
  61. WALLPAPER_PICKER = 3,
  62. VOLUME_CONTROL = 4,
  63. CHROME_PAGE = 5,
  64. WEB_APP = 6,
  65. kMaxValue = WEB_APP,
  66. };
  67. // Records Arc.IntentHelper.OpenType UMA histogram.
  68. void RecordOpenType(ArcIntentHelperOpenType type) {
  69. UMA_HISTOGRAM_ENUMERATION("Arc.IntentHelper.OpenType", type);
  70. }
  71. // These values are persisted to logs. Entries should not be renumbered and
  72. // numeric values should never be reused.
  73. enum class OpenIntentAction {
  74. kUnknown = 0,
  75. kView = 1,
  76. kSend = 2,
  77. kSendMultiple = 3,
  78. kMaxValue = kSendMultiple,
  79. };
  80. void RecordOpenAppIntentAction(const mojom::LaunchIntentPtr& intent) {
  81. OpenIntentAction action = OpenIntentAction::kUnknown;
  82. if (intent->action == kIntentActionView) {
  83. action = OpenIntentAction::kView;
  84. } else if (intent->action == kIntentActionSend) {
  85. action = OpenIntentAction::kSend;
  86. } else if (intent->action == kIntentActionSendMultiple) {
  87. action = OpenIntentAction::kSendMultiple;
  88. }
  89. UMA_HISTOGRAM_ENUMERATION("Arc.IntentHelper.OpenAppWithIntentAction", action);
  90. }
  91. // Returns true if a Web App is allowed to be opened for the given URL.
  92. bool CanOpenWebAppForUrl(const GURL& url) {
  93. bool is_http_localhost =
  94. url.SchemeIs(url::kHttpScheme) && net::IsLocalhost(url);
  95. return url.is_valid() &&
  96. (url.SchemeIs(url::kHttpsScheme) || is_http_localhost);
  97. }
  98. } // namespace
  99. // static
  100. ArcIntentHelperBridge* ArcIntentHelperBridge::GetForBrowserContext(
  101. content::BrowserContext* context) {
  102. return ArcIntentHelperBridgeFactory::GetForBrowserContext(context);
  103. }
  104. // static
  105. ArcIntentHelperBridge* ArcIntentHelperBridge::GetForBrowserContextForTesting(
  106. content::BrowserContext* context) {
  107. return ArcIntentHelperBridgeFactory::GetForBrowserContextForTesting(context);
  108. }
  109. // static
  110. BrowserContextKeyedServiceFactory* ArcIntentHelperBridge::GetFactory() {
  111. return ArcIntentHelperBridgeFactory::GetInstance();
  112. }
  113. // static
  114. std::string ArcIntentHelperBridge::AppendStringToIntentHelperPackageName(
  115. const std::string& to_append) {
  116. return base::JoinString({kArcIntentHelperPackageName, to_append}, ".");
  117. }
  118. // static
  119. void ArcIntentHelperBridge::SetOpenUrlDelegate(OpenUrlDelegate* delegate) {
  120. g_open_url_delegate = delegate;
  121. }
  122. // static
  123. void ArcIntentHelperBridge::SetControlCameraAppDelegate(
  124. ControlCameraAppDelegate* delegate) {
  125. g_control_camera_app_delegate = delegate;
  126. }
  127. void ArcIntentHelperBridge::SetDelegate(std::unique_ptr<Delegate> delegate) {
  128. delegate_ = std::move(delegate);
  129. }
  130. ArcIntentHelperBridge::ArcIntentHelperBridge(content::BrowserContext* context,
  131. ArcBridgeService* bridge_service)
  132. : context_(context),
  133. arc_bridge_service_(bridge_service),
  134. allowed_arc_schemes_(std::cbegin(kArcSchemes), std::cend(kArcSchemes)) {
  135. arc_bridge_service_->intent_helper()->SetHost(this);
  136. }
  137. ArcIntentHelperBridge::~ArcIntentHelperBridge() {
  138. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  139. arc_bridge_service_->intent_helper()->SetHost(nullptr);
  140. }
  141. void ArcIntentHelperBridge::Shutdown() {
  142. for (auto& observer : observer_list_)
  143. observer.OnArcIntentHelperBridgeShutdown();
  144. }
  145. void ArcIntentHelperBridge::OnIconInvalidated(const std::string& package_name) {
  146. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  147. icon_loader_.InvalidateIcons(package_name);
  148. for (auto& observer : observer_list_)
  149. observer.OnIconInvalidated(package_name);
  150. }
  151. void ArcIntentHelperBridge::OnIntentFiltersUpdated(
  152. std::vector<IntentFilter> filters) {
  153. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  154. intent_filters_.clear();
  155. for (auto& filter : filters)
  156. intent_filters_[filter.package_name()].push_back(std::move(filter));
  157. for (auto& observer : observer_list_)
  158. observer.OnIntentFiltersUpdated(absl::nullopt);
  159. }
  160. void ArcIntentHelperBridge::OnOpenDownloads() {
  161. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  162. RecordOpenType(ArcIntentHelperOpenType::DOWNLOADS);
  163. ash::NewWindowDelegate::GetInstance()->OpenDownloadsFolder();
  164. }
  165. void ArcIntentHelperBridge::OnOpenUrl(const std::string& url) {
  166. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  167. RecordOpenType(ArcIntentHelperOpenType::URL);
  168. // Converts |url| to a fixed-up one and checks validity.
  169. const GURL gurl(url_formatter::FixupURL(url, /*desired_tld=*/std::string()));
  170. if (!gurl.is_valid())
  171. return;
  172. if (allowed_arc_schemes_.find(gurl.scheme()) != allowed_arc_schemes_.end())
  173. g_open_url_delegate->OpenUrlFromArc(gurl);
  174. }
  175. void ArcIntentHelperBridge::OnOpenCustomTab(const std::string& url,
  176. int32_t task_id,
  177. OnOpenCustomTabCallback callback) {
  178. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  179. RecordOpenType(ArcIntentHelperOpenType::CUSTOM_TAB);
  180. // Converts |url| to a fixed-up one and checks validity.
  181. const GURL gurl(url_formatter::FixupURL(url, /*desired_tld=*/std::string()));
  182. if (!gurl.is_valid() ||
  183. allowed_arc_schemes_.find(gurl.scheme()) == allowed_arc_schemes_.end()) {
  184. std::move(callback).Run(mojo::NullRemote());
  185. return;
  186. }
  187. g_open_url_delegate->OpenArcCustomTab(gurl, task_id, std::move(callback));
  188. }
  189. void ArcIntentHelperBridge::OnOpenChromePage(mojom::ChromePage page) {
  190. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  191. RecordOpenType(ArcIntentHelperOpenType::CHROME_PAGE);
  192. g_open_url_delegate->OpenChromePageFromArc(page);
  193. }
  194. void ArcIntentHelperBridge::FactoryResetArc() {
  195. if (delegate_)
  196. delegate_->ResetArc();
  197. }
  198. void ArcIntentHelperBridge::OpenWallpaperPicker() {
  199. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  200. RecordOpenType(ArcIntentHelperOpenType::WALLPAPER_PICKER);
  201. ash::WallpaperController::Get()->OpenWallpaperPickerIfAllowed();
  202. }
  203. void ArcIntentHelperBridge::OpenVolumeControl() {
  204. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  205. RecordOpenType(ArcIntentHelperOpenType::VOLUME_CONTROL);
  206. auto* audio = ArcAudioBridge::GetForBrowserContext(context_);
  207. DCHECK(audio);
  208. audio->ShowVolumeControls();
  209. }
  210. void ArcIntentHelperBridge::OnOpenWebApp(const std::string& url) {
  211. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  212. RecordOpenType(ArcIntentHelperOpenType::WEB_APP);
  213. // Converts |url| to a fixed-up one and checks validity.
  214. const GURL gurl(url_formatter::FixupURL(url, /*desired_tld=*/std::string()));
  215. // Web app launches should only be invoked on HTTPS URLs.
  216. if (CanOpenWebAppForUrl(gurl))
  217. g_open_url_delegate->OpenWebAppFromArc(gurl);
  218. }
  219. // TODO(b/200873831): Delete this anytime on 2022.
  220. void ArcIntentHelperBridge::RecordShareFilesMetricsDeprecated(
  221. mojom::ShareFiles flag) {
  222. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  223. // Record metrics coming from ARC, these are related Share files feature
  224. // stability.
  225. LOG(ERROR) << "Arc.ShareFilesOnExit is deprecated, erasing incoming";
  226. }
  227. void ArcIntentHelperBridge::LaunchCameraApp(uint32_t intent_id,
  228. arc::mojom::CameraIntentMode mode,
  229. bool should_handle_result,
  230. bool should_down_scale,
  231. bool is_secure,
  232. int32_t task_id) {
  233. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  234. std::string mode_str =
  235. mode == arc::mojom::CameraIntentMode::PHOTO ? "photo" : "video";
  236. std::stringstream queries;
  237. queries << "?intentId=" << intent_id << "&mode=" << mode_str
  238. << "&shouldHandleResult=" << should_handle_result
  239. << "&shouldDownScale=" << should_down_scale
  240. << "&isSecure=" << is_secure;
  241. g_control_camera_app_delegate->LaunchCameraApp(queries.str(), task_id);
  242. }
  243. void ArcIntentHelperBridge::OnIntentFiltersUpdatedForPackage(
  244. const std::string& package_name,
  245. std::vector<IntentFilter> filters) {
  246. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  247. intent_filters_.erase(package_name);
  248. if (filters.size() > 0)
  249. intent_filters_[package_name] = std::move(filters);
  250. for (auto& observer : observer_list_)
  251. observer.OnIntentFiltersUpdated(package_name);
  252. }
  253. void ArcIntentHelperBridge::CloseCameraApp() {
  254. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  255. g_control_camera_app_delegate->CloseCameraApp();
  256. }
  257. void ArcIntentHelperBridge::IsChromeAppEnabled(
  258. arc::mojom::ChromeApp app,
  259. IsChromeAppEnabledCallback callback) {
  260. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  261. if (app == arc::mojom::ChromeApp::CAMERA) {
  262. std::move(callback).Run(
  263. g_control_camera_app_delegate->IsCameraAppEnabled());
  264. return;
  265. }
  266. NOTREACHED() << "Unknown chrome app";
  267. std::move(callback).Run(false);
  268. }
  269. void ArcIntentHelperBridge::OnSupportedLinksChanged(
  270. std::vector<arc::mojom::SupportedLinksPtr> added_packages,
  271. std::vector<arc::mojom::SupportedLinksPtr> removed_packages,
  272. arc::mojom::SupportedLinkChangeSource source) {
  273. for (auto& observer : observer_list_)
  274. observer.OnArcSupportedLinksChanged(added_packages, removed_packages,
  275. source);
  276. }
  277. void ArcIntentHelperBridge::OnDownloadAdded(
  278. const std::string& relative_path_as_string,
  279. const std::string& owner_package_name) {
  280. const base::FilePath download_folder("Download/");
  281. const base::FilePath relative_path(relative_path_as_string);
  282. // Observers should *not* be called when a download is added outside of the
  283. // Download/ folder. This would be an unexpected event coming from ARC but
  284. // we protect against it because ARC is treated as an untrusted source.
  285. if (!download_folder.IsParent(relative_path) ||
  286. relative_path.ReferencesParent()) {
  287. return;
  288. }
  289. for (auto& observer : observer_list_)
  290. observer.OnArcDownloadAdded(relative_path, owner_package_name);
  291. }
  292. void ArcIntentHelperBridge::OnOpenAppWithIntent(
  293. const GURL& start_url,
  294. arc::mojom::LaunchIntentPtr intent) {
  295. // Web app launches should only be invoked on HTTPS URLs.
  296. if (CanOpenWebAppForUrl(start_url)) {
  297. RecordOpenType(ArcIntentHelperOpenType::WEB_APP);
  298. RecordOpenAppIntentAction(intent);
  299. g_open_url_delegate->OpenAppWithIntent(start_url, std::move(intent));
  300. }
  301. }
  302. void ArcIntentHelperBridge::OnOpenGlobalActions() {
  303. ash::PowerButtonControllerBase::Get()->OnArcPowerButtonMenuEvent();
  304. }
  305. void ArcIntentHelperBridge::OnCloseSystemDialogs() {
  306. ash::PowerButtonControllerBase::Get()->CancelPowerButtonEvent();
  307. }
  308. ArcIntentHelperBridge::GetResult ArcIntentHelperBridge::GetActivityIcons(
  309. const std::vector<ActivityName>& activities,
  310. OnIconsReadyCallback callback) {
  311. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  312. return icon_loader_.GetActivityIcons(activities, std::move(callback));
  313. }
  314. void ArcIntentHelperBridge::SetAdaptiveIconDelegate(
  315. AdaptiveIconDelegate* delegate) {
  316. icon_loader_.SetAdaptiveIconDelegate(delegate);
  317. }
  318. void ArcIntentHelperBridge::AddObserver(ArcIntentHelperObserver* observer) {
  319. observer_list_.AddObserver(observer);
  320. }
  321. void ArcIntentHelperBridge::RemoveObserver(ArcIntentHelperObserver* observer) {
  322. observer_list_.RemoveObserver(observer);
  323. }
  324. bool ArcIntentHelperBridge::HasObserver(
  325. ArcIntentHelperObserver* observer) const {
  326. return observer_list_.HasObserver(observer);
  327. }
  328. void ArcIntentHelperBridge::HandleCameraResult(
  329. uint32_t intent_id,
  330. arc::mojom::CameraIntentAction action,
  331. const std::vector<uint8_t>& data,
  332. arc::mojom::IntentHelperInstance::HandleCameraResultCallback callback) {
  333. auto* arc_service_manager = arc::ArcServiceManager::Get();
  334. arc::mojom::IntentHelperInstance* instance = nullptr;
  335. if (arc_service_manager) {
  336. instance = ARC_GET_INSTANCE_FOR_METHOD(
  337. arc_service_manager->arc_bridge_service()->intent_helper(),
  338. HandleCameraResult);
  339. }
  340. if (!instance) {
  341. LOG(ERROR) << "Failed to get instance for HandleCameraResult().";
  342. std::move(callback).Run(false);
  343. return;
  344. }
  345. instance->HandleCameraResult(intent_id, action, data, std::move(callback));
  346. }
  347. void ArcIntentHelperBridge::SendNewCaptureBroadcast(bool is_video,
  348. std::string file_path) {
  349. auto* arc_service_manager = arc::ArcServiceManager::Get();
  350. arc::mojom::IntentHelperInstance* instance = nullptr;
  351. if (arc_service_manager) {
  352. instance = ARC_GET_INSTANCE_FOR_METHOD(
  353. arc_service_manager->arc_bridge_service()->intent_helper(),
  354. SendBroadcast);
  355. }
  356. if (!instance) {
  357. LOG(ERROR) << "Failed to get instance for SendBroadcast().";
  358. return;
  359. }
  360. std::string action =
  361. is_video ? "org.chromium.arc.intent_helper.ACTION_SEND_NEW_VIDEO"
  362. : "org.chromium.arc.intent_helper.ACTION_SEND_NEW_PICTURE";
  363. base::Value::Dict value;
  364. value.Set("file_path", file_path);
  365. std::string extras;
  366. base::JSONWriter::Write(value, &extras);
  367. instance->SendBroadcast(action, "org.chromium.arc.intent_helper",
  368. /*cls=*/std::string(), extras);
  369. }
  370. // static
  371. std::vector<mojom::IntentHandlerInfoPtr>
  372. ArcIntentHelperBridge::FilterOutIntentHelper(
  373. std::vector<mojom::IntentHandlerInfoPtr> handlers) {
  374. std::vector<mojom::IntentHandlerInfoPtr> handlers_filtered;
  375. for (auto& handler : handlers) {
  376. if (handler->package_name == kArcIntentHelperPackageName)
  377. continue;
  378. handlers_filtered.push_back(std::move(handler));
  379. }
  380. return handlers_filtered;
  381. }
  382. const std::vector<IntentFilter>&
  383. ArcIntentHelperBridge::GetIntentFilterForPackage(
  384. const std::string& package_name) {
  385. return intent_filters_[package_name];
  386. }
  387. } // namespace arc