Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: e78bb839774e5a3b9fdfca31f4bf541f6c412446 [file] [log] [blame] [view]
Colin Blundell196d72d32020-07-14 13:10:111This directory holds the core logic that Chrome uses to launch external intents
Michael Thiessendac7b0a2022-11-04 17:20:022on Android. External Navigation is surprisingly subtle, with implications on
Colin Blundell196d72d32020-07-14 13:10:113privacy, security, and platform integration. This document goes through the
4following aspects:
Michael Thiessendac7b0a2022-11-04 17:20:025- Motivation
6- Examples of supported and unsupported navigations
7- What happens when a navigation is blocked
8- Code Structure
9- Additional Details
Colin Blundell196d72d32020-07-14 13:10:1110- Embedding of the component
Colin Blundell196d72d32020-07-14 13:10:1111- Opportunities for code health improvements in the component
12
Michael Thiessendac7b0a2022-11-04 17:20:0213Throughout this document we will be using Chrome's exercising of this component
14for illustration.
Colin Blundell196d72d32020-07-14 13:10:1115
Michael Thiessendac7b0a2022-11-04 17:20:0216# Motivation
17
18The goal of External Navigation in Chrome is to seamlessly and securely
19integrate the web with the Android app ecosystem. If the user has installed an
20app for a website, then clicking a link to that website should cause the app to
21open.
22
23# Supported Flows
24
25There are many ways web and app developers use intents, here are a few examples:
26
27- Clicking a link to [https://www.youtube.com](https://www.youtube.com/) opens
28 the Youtube app.
29- Clicking a link to
30[intent://www.youtube.com#Intent;scheme=https;action=android.intent.action.VIEW;S.browser\_fallback\_url=https%3A%2F%2Fwww.example.com/;end](http://www.youtube.com/#Intent;scheme=https;action=android.intent.action.VIEW;S.browser_fallback_url=https%3A%2F%2Fwww.example.com/;end)
31 opens the Youtube app if installed, and example.com if not.
32- An app opens a URL redirector in Chrome, which does a server redirect to an
33 app link without any user interaction.
34- Clicking a link triggers an async XHR to perform sign-in, then client
35 redirects to an app after receiving the response.
36- An app opens a CCT to start a payment, the user manually switches to their
37 bank app to validate the payment, then later returns to the CCT, which, without
38 user input, redirects back to the app after the payment is confirmed.
39
40# Unsupported Flows
41
42## In order to protect users, there are many things we don't allow:
43
44- Launching an app without a
45[Verified App Link](https://developer.android.com/training/app-links/verify-android-applinks)
46 (or specialized intent filter pre-S) if the scheme can instead be handled in
47 Chrome.
48- Explicit intents (i.e. with a component specified), or intent without the
49 BROWSABLE category (which Chrome always adds to intents).
50- Launching an app from a tab not currently visible to the user.
51- Launching an app without
52[user activation](https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation)
53 (unless doing trusted CCT/TWA navigation).
54- Launching an app after a long timeout (as the user won't be expecting it).
55- Launching certain schemes like file:, content: and other chrome-internal
56 schemes.
57- Launching Instant Apps directly on old Android versions.
58- Launching apps from tab restore, back/forward, reload.
59- Launching apps from fallback URLs or repeatedly attempting to launch apps with
60 the same user activation (prevents fingerprinting).
61- Launching arbitrary URLs in other browsers that may be behind on security
62 patches.
63
64## Other reasons to keep navigation in Chrome:
65
66- Navigations from Chrome UI initially load in Chrome, but are allowed to
67 redirect to apps.
68- Form submissions are expected to be sent to a server, not an app, unless
69 redirected.
70- Intents URLs load in Chrome as they were intentionally sent to Chrome,
71 though may redirect out.
72- If an intent redirects to a URL for an Activity that the initial intent also
73 matched (i.e. the set of apps supporting the navigation hasn't changed), we
74 stay in Chrome as the user has already presumably chosen Chrome over the app.
75- If an intent explicitly targeted the Chrome package, we interpret that as a
76 strong signal the intent was supposed to stay in Chrome even through redirects.
77- If the user is in incognito, keep them in incognito unless Chrome can't handle
78 the URL, in which case we ask the user if they would like to leave.
79- Same-host navigations shouldn't leave Chrome unless the list of handling apps
80 changes (eg. going from google.com/search to google.com/maps should launch the
81 Maps app, but going to google.com/search?page=2 should stay in Chrome).
82- If in CCT or other contexts where the disambiguation dialog would be shown,
83 but Chrome doesn't have an entry to put on it, but can handle the URL, the URL
84 stays in Chrome.
85
86## Debugging blocked Navigations
87
88When trying to debug why a navigation was blocked, it's helpful to turn on
89"External Navigation Debug Logs" in chrome://flags, which will cause detailed
90logging to be output to logcat under the "UrlHandler" tag.
91
92# What happens when a navigation is blocked
93
94What happens when a navigation is blocked depends on the reason for the
95navigation being blocked. Some URLs should never be launched to apps under any
96circumstances, like content: schemes. In cases like this, the navigation will
97simply be ignored, and a warning will be printed to the developer console. In
98other cases, like when the external navigation was disallowed because Chrome
99thinks the user probably expected to stay in Chrome (like navigation from typing
100into the URL bar), it depends on whether Chrome can handle the link or not. If
101Chrome can handle the link itself, or a fallback URL for an intent: URI exists,
102it simply loads in Chrome. If Chrome can't handle the link, a Message is
103displayed to the user asking them if they would like to leave Chrome.
104
105# Code structure
106
107The vast majority of the logic controlling whether a navigation leaves Chrome
108lives in **ExternalNavigationHandler#shouldOverrideUrlLoading**. This function
109makes use of the **ExternalNavigationDelegate** to allow content embedders to
110customize the behavior, and the **RedirectHandler** to track Navigation history.
111
Michael Thiessenc88960c2023-02-01 13:48:41112There are 2 ways shouldOverrideUrlLoading gets invoked:
Michael Thiessendac7b0a2022-11-04 17:20:02113
114- Main frame navigations
115 - Called through a NavigationThrottle in intercept\_navigation\_delegate.cc
116- Subframe navigations
117 - Only intercepted for external protocols
118 - Called through ExternalProtocolHandler::LaunchUrl
Michael Thiessendac7b0a2022-11-04 17:20:02119
120# Additional Details
Colin Blundell196d72d32020-07-14 13:10:11121
122## InterceptNavigationDelegateImpl
123
Michael Thiessendac7b0a2022-11-04 17:20:02124The entrypoint to the component is usually InterceptNavigationDelegateImpl.java,
125which layers on top of //components/navigation_interception's support for
Colin Blundell196d72d32020-07-14 13:10:11126NavigationThrottles that delegate to Java for their core logic. Within the
127context of Chrome, InterceptNavigationDelegateImpl is a per-Tab (or Tab-like,
Michael Thiessendac7b0a2022-11-04 17:20:02128e.g. OverlayPanel) object that intercepts every main frame navigation made in
129the given Tab and determines whether the navigation should result in an external
130intent being launched. The key method is
Colin Blundell196d72d32020-07-14 13:10:11131InterceptNavigationDelegateImpl#shouldIgnoreNavigation(). This method sets up
132state related to the current navigation and then invokes
133ExternalNavigationHandler to do the heavy lifting of determining whether the
134navigation should result in an external intent being launched. If so,
135InterceptNavigationDelegateImpl does cleanup in the given Tab, including
136restoring the navigation state to what it was before the navigation chain that
137resulted in this intent being launched and potentially closing the Tab itself if
138opening the Tab led to the intent launch.
139
140## ExternalNavigationHandler
141
142ExternalNavigationHandler is the core of the component. It handles all of the
Michael Thiessendac7b0a2022-11-04 17:20:02143intent launching semantics that Chrome has accumulated over 10+ years. See the
144list of supported and unsupported flows above - this class is responsible for
145the vast majority of that logic.
Colin Blundell196d72d32020-07-14 13:10:11146
Michael Thiessendac7b0a2022-11-04 17:20:02147ExternalNavigationHandler.java is a large and complex class. The key external
148entrypoint is ExternalNavigationHandler#shouldOverrideUrlLoading(), and the
149method that actually holds the core logic for when and how external intents
150should be launched is
151ExternalNavigationHandler#shouldOverrideUrlLoadingInternal().
Colin Blundell196d72d32020-07-14 13:10:11152
153## RedirectHandler
154
155This class tracks state across navigations in order to aid
156InterceptNavigationDelegateImpl and ExternalNavigationHandler both in making
157decisions on whether to launch an intent for a given navigation and in properly
158handling the state within a Tab in the event that an intent is launched. Most
159notably, it provides information about the redirect chain (if any) that a given
160navigation is part of and whether the set of apps that can handle an intent
161changes while processing the redirect chain. ExternalNavigationHandlerImpl uses
162this information as part of its determination process (e.g., for determining
163whether an intent can be launched from a user-typed navigation).
164InterceptNavigationDelegateImpl also uses this information to determine how to
165restore the navigation state in its Tab after an intent being launched.
166
167## ExternalNavigationDelegate and InterceptNavigationDelegateClient
168
169These interfaces allow embedders to customize the behavior of the component (see
170the next section for details). Note that they should *not* be used to customize
171the behavior of the components for tests; if that is necessary (e.g., to stub
172out a production method), instead make the method protected and
173@VisibleForTesting and override it as suitable in a test subclass.
174
Michael Thiessendac7b0a2022-11-04 17:20:02175## Other useful information
176
177- Resource requests like XHR are not typically visible to the browser process,
178 but sites often perform a client redirect to an app upon their completion. To
179 support this we have a separate IPC coming from the renderer to update the
180 RedirectHandler, see InterceptNavigationDelegate::OnResourceRequestWithGesture.
181- Client-side redirects are challenging to deal with in general, as they're not
182 considered part of the previous navigation, not directly associated with any
183 user gesture, and generally poorly defined. The RedirectHandler deals with this
184 by treating all renderer-initiated navigations without a user gesture as a
185 client redirect on the previous navigation. This can lead to indefinite
186 redirect chains, so in order to make sure an unattended page isn't redirecting,
187 and the user isn't caught off guard, a hard 15 second timeout from the
188 navigation with a user gesture is used.
189
Colin Blundell196d72d32020-07-14 13:10:11190# Embedding the Component
191
192To embed the component, it's necessary to install
193InterceptNavigationDelegateImpl for each "tab" of the embedder (where a tab is
Scott Violet447e4fe2023-09-19 16:47:03194the embedder-level object that holds a WebContents).
Colin Blundell196d72d32020-07-14 13:10:11195
196There are two interfaces that the embedder must implement in order to embed the
197component: InterceptNavigationDelegateClient and ExternalNavigationDelegate.
Scott Violet447e4fe2023-09-19 16:47:03198
Colin Blundell196d72d32020-07-14 13:10:11199# Opportunities for Code Health Improvements
200- For historical reasons, there is overlap between the
201 InterceptNavigationDelegateClient and ExternalNavigationDelegate interfaces.
202 It is likely that the collective API surface could be thinned.
203- It is also potentially even possible that the two interfaces could ultimately
204 be merged into one.