OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.customtabs; | 5 package org.chromium.chrome.browser.customtabs; |
6 | 6 |
7 import android.app.ActivityManager; | 7 import android.app.ActivityManager; |
8 import android.app.Application; | 8 import android.app.Application; |
9 import android.app.PendingIntent; | 9 import android.app.PendingIntent; |
10 import android.content.Context; | 10 import android.content.Context; |
(...skipping 10 matching lines...) Expand all Loading... | |
21 import android.os.SystemClock; | 21 import android.os.SystemClock; |
22 import android.support.customtabs.CustomTabsCallback; | 22 import android.support.customtabs.CustomTabsCallback; |
23 import android.support.customtabs.CustomTabsIntent; | 23 import android.support.customtabs.CustomTabsIntent; |
24 import android.support.customtabs.CustomTabsService; | 24 import android.support.customtabs.CustomTabsService; |
25 import android.support.customtabs.CustomTabsSessionToken; | 25 import android.support.customtabs.CustomTabsSessionToken; |
26 import android.text.TextUtils; | 26 import android.text.TextUtils; |
27 import android.util.Pair; | 27 import android.util.Pair; |
28 import android.widget.RemoteViews; | 28 import android.widget.RemoteViews; |
29 | 29 |
30 import org.chromium.base.CommandLine; | 30 import org.chromium.base.CommandLine; |
31 import org.chromium.base.ContextUtils; | |
31 import org.chromium.base.Log; | 32 import org.chromium.base.Log; |
32 import org.chromium.base.ThreadUtils; | 33 import org.chromium.base.ThreadUtils; |
33 import org.chromium.base.TimeUtils; | 34 import org.chromium.base.TimeUtils; |
34 import org.chromium.base.TraceEvent; | 35 import org.chromium.base.TraceEvent; |
35 import org.chromium.base.VisibleForTesting; | 36 import org.chromium.base.VisibleForTesting; |
36 import org.chromium.base.annotations.SuppressFBWarnings; | 37 import org.chromium.base.annotations.SuppressFBWarnings; |
37 import org.chromium.base.library_loader.ProcessInitException; | 38 import org.chromium.base.library_loader.ProcessInitException; |
38 import org.chromium.base.metrics.RecordHistogram; | 39 import org.chromium.base.metrics.RecordHistogram; |
39 import org.chromium.chrome.R; | 40 import org.chromium.chrome.R; |
40 import org.chromium.chrome.browser.AppHooks; | 41 import org.chromium.chrome.browser.AppHooks; |
41 import org.chromium.chrome.browser.ChromeApplication; | 42 import org.chromium.chrome.browser.ChromeApplication; |
42 import org.chromium.chrome.browser.ChromeFeatureList; | 43 import org.chromium.chrome.browser.ChromeFeatureList; |
43 import org.chromium.chrome.browser.IntentHandler; | 44 import org.chromium.chrome.browser.IntentHandler; |
44 import org.chromium.chrome.browser.WarmupManager; | 45 import org.chromium.chrome.browser.WarmupManager; |
45 import org.chromium.chrome.browser.device.DeviceClassManager; | 46 import org.chromium.chrome.browser.device.DeviceClassManager; |
46 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; | 47 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; |
47 import org.chromium.chrome.browser.metrics.PageLoadMetrics; | 48 import org.chromium.chrome.browser.metrics.PageLoadMetrics; |
48 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; | 49 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; |
49 import org.chromium.chrome.browser.preferences.PrefServiceBridge; | 50 import org.chromium.chrome.browser.preferences.PrefServiceBridge; |
50 import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler; | 51 import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler; |
51 import org.chromium.chrome.browser.profiles.Profile; | 52 import org.chromium.chrome.browser.profiles.Profile; |
52 import org.chromium.chrome.browser.tab.Tab; | 53 import org.chromium.chrome.browser.tab.Tab; |
53 import org.chromium.chrome.browser.util.IntentUtils; | 54 import org.chromium.chrome.browser.util.IntentUtils; |
54 import org.chromium.chrome.browser.util.UrlUtilities; | 55 import org.chromium.chrome.browser.util.UrlUtilities; |
55 import org.chromium.content.browser.ChildProcessLauncherHelper; | 56 import org.chromium.content.browser.ChildProcessLauncherHelper; |
56 import org.chromium.content_public.browser.LoadUrlParams; | 57 import org.chromium.content_public.browser.LoadUrlParams; |
57 import org.chromium.content_public.browser.WebContents; | 58 import org.chromium.content_public.browser.WebContents; |
58 import org.chromium.content_public.common.Referrer; | 59 import org.chromium.content_public.common.Referrer; |
60 import org.chromium.net.GURLUtils; | |
59 | 61 |
60 import java.io.BufferedReader; | 62 import java.io.BufferedReader; |
61 import java.io.FileReader; | 63 import java.io.FileReader; |
62 import java.io.IOException; | 64 import java.io.IOException; |
63 import java.util.List; | 65 import java.util.List; |
64 import java.util.concurrent.Callable; | 66 import java.util.concurrent.Callable; |
65 import java.util.concurrent.ExecutionException; | 67 import java.util.concurrent.ExecutionException; |
66 import java.util.concurrent.atomic.AtomicBoolean; | 68 import java.util.concurrent.atomic.AtomicBoolean; |
67 import java.util.concurrent.atomic.AtomicReference; | 69 import java.util.concurrent.atomic.AtomicReference; |
68 | 70 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
109 static final String DEBUG_OVERRIDE_KEY = | 111 static final String DEBUG_OVERRIDE_KEY = |
110 "android.support.customtabs.maylaunchurl.DEBUG_OVERRIDE"; | 112 "android.support.customtabs.maylaunchurl.DEBUG_OVERRIDE"; |
111 private static final int NO_OVERRIDE = 0; | 113 private static final int NO_OVERRIDE = 0; |
112 @VisibleForTesting | 114 @VisibleForTesting |
113 static final int NO_PRERENDERING = 1; | 115 static final int NO_PRERENDERING = 1; |
114 @VisibleForTesting | 116 @VisibleForTesting |
115 static final int PREFETCH_ONLY = 2; | 117 static final int PREFETCH_ONLY = 2; |
116 @VisibleForTesting | 118 @VisibleForTesting |
117 static final int HIDDEN_TAB = 3; | 119 static final int HIDDEN_TAB = 3; |
118 | 120 |
121 @VisibleForTesting | |
122 static final String REDIRECT_ENDPOINT_KEY = "android.support.customtabs.REDI RECT_ENDPOINT"; | |
Yusuf
2017/07/06 06:34:42
some todo around moving this to support lib?
Benoit L
2017/07/07 11:30:56
Done.
| |
123 | |
119 private static AtomicReference<CustomTabsConnection> sInstance = new AtomicR eference<>(); | 124 private static AtomicReference<CustomTabsConnection> sInstance = new AtomicR eference<>(); |
120 | 125 |
121 /** Holds the parameters for the current speculation. */ | 126 /** Holds the parameters for the current speculation. */ |
122 @VisibleForTesting | 127 @VisibleForTesting |
123 static final class SpeculationParams { | 128 static final class SpeculationParams { |
124 @VisibleForTesting | 129 @VisibleForTesting |
125 static final int NO_SPECULATION = 0; | 130 static final int NO_SPECULATION = 0; |
126 @VisibleForTesting | 131 @VisibleForTesting |
127 static final int PREFETCH = 1; | 132 static final int PREFETCH = 1; |
128 @VisibleForTesting | 133 @VisibleForTesting |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
339 } | 344 } |
340 } finally { | 345 } finally { |
341 TraceEvent.end("CustomTabsConnection.warmupInternal"); | 346 TraceEvent.end("CustomTabsConnection.warmupInternal"); |
342 } | 347 } |
343 mWarmupHasBeenFinished.set(true); | 348 mWarmupHasBeenFinished.set(true); |
344 } | 349 } |
345 }); | 350 }); |
346 return true; | 351 return true; |
347 } | 352 } |
348 | 353 |
349 /** @return the URL converted to string, or null if it's invalid. */ | 354 /** @return the URL or null if it's invalid. */ |
350 private static String checkAndConvertUri(Uri uri) { | 355 private boolean isValid(Uri uri) { |
351 if (uri == null) return null; | 356 if (uri == null) return false; |
352 // Don't do anything for unknown schemes. Not having a scheme is allowed , as we allow | 357 // Don't do anything for unknown schemes. Not having a scheme is allowed , as we allow |
353 // "www.example.com". | 358 // "www.example.com". |
354 String scheme = uri.normalizeScheme().getScheme(); | 359 String scheme = uri.normalizeScheme().getScheme(); |
355 boolean allowedScheme = scheme == null || scheme.equals("http") || schem e.equals("https"); | 360 boolean allowedScheme = scheme == null || scheme.equals("http") || schem e.equals("https"); |
356 if (!allowedScheme) return null; | 361 if (!allowedScheme) return false; |
357 return uri.toString(); | 362 return true; |
358 } | 363 } |
359 | 364 |
360 /** | 365 /** |
361 * High confidence mayLaunchUrl() call, that is: | 366 * High confidence mayLaunchUrl() call, that is: |
362 * - Tries to prerender if possible. | 367 * - Tries to prerender if possible. |
363 * - An empty URL cancels the current prerender if any. | 368 * - An empty URL cancels the current prerender if any. |
364 * - If prerendering is not possible, makes sure that there is a spare rende rer. | 369 * - If prerendering is not possible, makes sure that there is a spare rende rer. |
365 */ | 370 */ |
366 private void highConfidenceMayLaunchUrl(CustomTabsSessionToken session, | 371 private void highConfidenceMayLaunchUrl(CustomTabsSessionToken session, |
367 int uid, String url, Bundle extras, List<Bundle> otherLikelyBundles) { | 372 int uid, String url, Bundle extras, List<Bundle> otherLikelyBundles) { |
(...skipping 30 matching lines...) Expand all Loading... | |
398 if (likelyBundles == null) return false; | 403 if (likelyBundles == null) return false; |
399 WarmupManager warmupManager = WarmupManager.getInstance(); | 404 WarmupManager warmupManager = WarmupManager.getInstance(); |
400 Profile profile = Profile.getLastUsedProfile(); | 405 Profile profile = Profile.getLastUsedProfile(); |
401 for (Bundle bundle : likelyBundles) { | 406 for (Bundle bundle : likelyBundles) { |
402 Uri uri; | 407 Uri uri; |
403 try { | 408 try { |
404 uri = IntentUtils.safeGetParcelable(bundle, CustomTabsService.KE Y_URL); | 409 uri = IntentUtils.safeGetParcelable(bundle, CustomTabsService.KE Y_URL); |
405 } catch (ClassCastException e) { | 410 } catch (ClassCastException e) { |
406 continue; | 411 continue; |
407 } | 412 } |
408 String url = checkAndConvertUri(uri); | 413 if (isValid(uri)) { |
409 if (url != null) { | 414 warmupManager.maybePreconnectUrlAndSubResources(profile, uri.toS tring()); |
410 warmupManager.maybePreconnectUrlAndSubResources(profile, url); | |
411 atLeastOneUrl = true; | 415 atLeastOneUrl = true; |
412 } | 416 } |
413 } | 417 } |
414 return atLeastOneUrl; | 418 return atLeastOneUrl; |
415 } | 419 } |
416 | 420 |
417 public boolean mayLaunchUrl(CustomTabsSessionToken session, Uri url, Bundle extras, | 421 public boolean mayLaunchUrl(CustomTabsSessionToken session, Uri url, Bundle extras, |
418 List<Bundle> otherLikelyBundles) { | 422 List<Bundle> otherLikelyBundles) { |
419 try { | 423 try { |
420 TraceEvent.begin("CustomTabsConnection.mayLaunchUrl"); | 424 TraceEvent.begin("CustomTabsConnection.mayLaunchUrl"); |
421 boolean success = mayLaunchUrlInternal(session, url, extras, otherLi kelyBundles); | 425 boolean success = mayLaunchUrlInternal(session, url, extras, otherLi kelyBundles); |
422 logCall("mayLaunchUrl(" + url + ")", success); | 426 logCall("mayLaunchUrl(" + url + ")", success); |
423 return success; | 427 return success; |
424 } finally { | 428 } finally { |
425 TraceEvent.end("CustomTabsConnection.mayLaunchUrl"); | 429 TraceEvent.end("CustomTabsConnection.mayLaunchUrl"); |
426 } | 430 } |
427 } | 431 } |
428 | 432 |
429 private boolean mayLaunchUrlInternal(final CustomTabsSessionToken session, U ri url, | 433 private boolean mayLaunchUrlInternal(final CustomTabsSessionToken session, U ri url, |
430 final Bundle extras, final List<Bundle> otherLikelyBundles) { | 434 final Bundle extras, final List<Bundle> otherLikelyBundles) { |
431 final boolean lowConfidence = | 435 final boolean lowConfidence = |
432 (url == null || TextUtils.isEmpty(url.toString())) && otherLikel yBundles != null; | 436 (url == null || TextUtils.isEmpty(url.toString())) && otherLikel yBundles != null; |
433 final String urlString = checkAndConvertUri(url); | 437 final String urlString = isValid(url) ? url.toString() : null; |
434 if (url != null && urlString == null && !lowConfidence) return false; | 438 if (url != null && urlString == null && !lowConfidence) return false; |
435 | 439 |
436 // Things below need the browser process to be initialized. | 440 // Things below need the browser process to be initialized. |
437 | 441 |
438 // Forbids warmup() from creating a spare renderer, as prerendering woul dn't reuse | 442 // Forbids warmup() from creating a spare renderer, as prerendering woul dn't reuse |
439 // it. Checking whether prerendering is enabled requires the native libr ary to be loaded, | 443 // it. Checking whether prerendering is enabled requires the native libr ary to be loaded, |
440 // which is not necessarily the case yet. | 444 // which is not necessarily the case yet. |
441 if (!warmupInternal(false)) return false; // Also does the foreground ch eck. | 445 if (!warmupInternal(false)) return false; // Also does the foreground ch eck. |
442 | 446 |
443 final int uid = Binder.getCallingUid(); | 447 final int uid = Binder.getCallingUid(); |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
718 SPECULATION_STATUS_ON_SWAP_BACKGROUND_TAB_NOT_MATCHE D); | 722 SPECULATION_STATUS_ON_SWAP_BACKGROUND_TAB_NOT_MATCHE D); |
719 tab.destroy(); | 723 tab.destroy(); |
720 } | 724 } |
721 } | 725 } |
722 } finally { | 726 } finally { |
723 TraceEvent.end("CustomTabsConnection.takeHiddenTab"); | 727 TraceEvent.end("CustomTabsConnection.takeHiddenTab"); |
724 } | 728 } |
725 return null; | 729 return null; |
726 } | 730 } |
727 | 731 |
732 /** | |
733 * Called when an intent is handled by either an existing or a new CustomTab Activity. | |
734 * | |
735 * @param session Session extracted from the intent. | |
736 * @param url URL extracted from the intent. | |
737 * @param intent incoming intent. | |
738 */ | |
739 void onHandledIntent(CustomTabsSessionToken session, String url, Intent inte nt) { | |
740 // For the preconnection to not be a no-op, we need more than just the n ative library. | |
741 Context context = ContextUtils.getApplicationContext(); | |
742 if (!ChromeBrowserInitializer.getInstance(context).hasNativeInitializati onCompleted()) { | |
743 return; | |
744 } | |
745 if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_REDIRECT_PRECONNE CT)) return; | |
746 | |
747 // Conditions: | |
748 // - There is a valid redirect endpoint. | |
749 // - The URL's origin is first party with respect to the app. | |
750 Uri redirectEndpoint = intent.getParcelableExtra(REDIRECT_ENDPOINT_KEY); | |
Yusuf
2017/07/06 06:34:41
does it make sense to have this logic be in Custom
Benoit L
2017/07/07 11:30:56
This talks to ClientManager, and also I find it co
| |
751 if (redirectEndpoint == null || !isValid(redirectEndpoint)) return; | |
752 | |
753 String origin = GURLUtils.getOrigin(url); | |
754 if (origin == null) return; | |
755 if (!mClientManager.isFirstPartyOriginForSession(session, Uri.parse(orig in))) return; | |
Yusuf
2017/07/06 06:34:41
Going back all the way to how we handle isValidOri
Benoit L
2017/07/07 11:30:55
That would be a neat solution indeed.
However it
| |
756 | |
757 WarmupManager.getInstance().maybePreconnectUrlAndSubResources( | |
758 Profile.getLastUsedProfile(), redirectEndpoint.toString()); | |
Yusuf
2017/07/06 06:34:41
getLastUsedProfile().getOriginalProfile() to avoid
Benoit L
2017/07/07 11:30:56
Thanks!
Done.
| |
759 } | |
760 | |
728 /** See {@link ClientManager#getReferrerForSession(CustomTabsSessionToken)} */ | 761 /** See {@link ClientManager#getReferrerForSession(CustomTabsSessionToken)} */ |
729 public Referrer getReferrerForSession(CustomTabsSessionToken session) { | 762 public Referrer getReferrerForSession(CustomTabsSessionToken session) { |
730 return mClientManager.getReferrerForSession(session); | 763 return mClientManager.getReferrerForSession(session); |
731 } | 764 } |
732 | 765 |
733 /** @see ClientManager#shouldHideDomainForSession(CustomTabsSessionToken) */ | 766 /** @see ClientManager#shouldHideDomainForSession(CustomTabsSessionToken) */ |
734 public boolean shouldHideDomainForSession(CustomTabsSessionToken session) { | 767 public boolean shouldHideDomainForSession(CustomTabsSessionToken session) { |
735 return mClientManager.shouldHideDomainForSession(session); | 768 return mClientManager.shouldHideDomainForSession(session); |
736 } | 769 } |
737 | 770 |
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1234 private static void recordSpeculationStatusOnStart(int status) { | 1267 private static void recordSpeculationStatusOnStart(int status) { |
1235 RecordHistogram.recordEnumeratedHistogram( | 1268 RecordHistogram.recordEnumeratedHistogram( |
1236 "CustomTabs.SpeculationStatusOnStart", status, SPECULATION_STATU S_ON_START_MAX); | 1269 "CustomTabs.SpeculationStatusOnStart", status, SPECULATION_STATU S_ON_START_MAX); |
1237 } | 1270 } |
1238 | 1271 |
1239 private static void recordSpeculationStatusOnSwap(int status) { | 1272 private static void recordSpeculationStatusOnSwap(int status) { |
1240 RecordHistogram.recordEnumeratedHistogram( | 1273 RecordHistogram.recordEnumeratedHistogram( |
1241 "CustomTabs.SpeculationStatusOnSwap", status, SPECULATION_STATUS _ON_SWAP_MAX); | 1274 "CustomTabs.SpeculationStatusOnSwap", status, SPECULATION_STATUS _ON_SWAP_MAX); |
1242 } | 1275 } |
1243 } | 1276 } |
OLD | NEW |