Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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; | 5 package org.chromium.chrome.browser; |
| 6 | 6 |
| 7 import android.os.SystemClock; | |
| 8 import android.util.LruCache; | |
| 7 import android.webkit.URLUtil; | 9 import android.webkit.URLUtil; |
| 8 | 10 |
| 9 import org.chromium.base.SysUtils; | 11 import org.chromium.base.SysUtils; |
| 12 import org.chromium.base.VisibleForTesting; | |
| 10 import org.chromium.blink.mojom.document_metadata.CopylessPaste; | 13 import org.chromium.blink.mojom.document_metadata.CopylessPaste; |
| 11 import org.chromium.blink.mojom.document_metadata.WebPage; | 14 import org.chromium.blink.mojom.document_metadata.WebPage; |
| 12 import org.chromium.chrome.browser.historyreport.AppIndexingReporter; | 15 import org.chromium.chrome.browser.historyreport.AppIndexingReporter; |
| 13 import org.chromium.chrome.browser.tab.Tab; | 16 import org.chromium.chrome.browser.tab.Tab; |
| 14 import org.chromium.content_public.browser.RenderFrameHost; | 17 import org.chromium.content_public.browser.RenderFrameHost; |
| 15 import org.chromium.content_public.browser.WebContents; | 18 import org.chromium.content_public.browser.WebContents; |
| 16 import org.chromium.services.service_manager.InterfaceProvider; | 19 import org.chromium.services.service_manager.InterfaceProvider; |
| 17 | 20 |
| 18 /** | 21 /** |
| 19 * This is the top-level CopylessPaste metadata extraction for AppIndexing. | 22 * This is the top-level CopylessPaste metadata extraction for AppIndexing. |
| 20 */ | 23 */ |
| 21 public class AppIndexingUtil { | 24 public class AppIndexingUtil { |
| 22 public static void extractCopylessPasteMetadata(final Tab tab) { | 25 private static final int CACHE_SIZE = 100; |
| 23 String url = tab.getUrl(); | 26 private static final int CACHE_VISIT_CUTOFF_MS = 60 * 60 * 1000; // 1 hour |
| 27 // Cache of recently seen urls. If a url is among the CACHE_SIZE most recent pages visited, and | |
| 28 // the visit was in the last CACHE_VISIT_CUTOFF_MS milliseconds, then we don 't parse the page, | |
|
wychen
2017/04/13 07:05:00
and the *parsing* was in the last ...
Our expirat
dproctor
2017/04/13 17:23:09
Thanks, yeah, the comparison is made based on the
| |
| 29 // and instead just report the view (not the content) to App Indexing. | |
| 30 private final LruCache<String, CacheEntry> mPageCache; | |
| 31 | |
| 32 public AppIndexingUtil() { | |
| 33 this(CACHE_SIZE); | |
| 34 } | |
| 35 | |
| 36 private AppIndexingUtil(int cacheSize) { | |
| 37 mPageCache = new LruCache<String, CacheEntry>(cacheSize); | |
| 38 } | |
| 39 | |
| 40 public void extractCopylessPasteMetadata(final Tab tab) { | |
| 41 final String url = tab.getUrl(); | |
| 24 boolean isHttpOrHttps = URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url ); | 42 boolean isHttpOrHttps = URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url ); |
| 25 if (SysUtils.isLowEndDevice() || tab.isIncognito() | 43 if (!isEnabledForDevice() || tab.isIncognito() || !isHttpOrHttps) { |
| 26 || !ChromeFeatureList.isEnabled(ChromeFeatureList.COPYLESS_PASTE ) | |
| 27 || !isHttpOrHttps) { | |
| 28 return; | 44 return; |
| 29 } | 45 } |
| 30 | 46 |
| 47 // There are three conditions that can occur with respect to the cache. | |
|
wychen
2017/04/13 07:05:00
We might want to add UMA to track the distribution
dproctor
2017/04/13 17:34:58
How about we add this in a follow-up cl?
wychen
2017/04/13 18:04:45
No problem.
| |
| 48 // 1. Cache hit, and an entity was found previously. Report only the pag e view to App | |
| 49 // Indexing. | |
| 50 // 2. Cache hit, but no entity was found. Ignore. | |
| 51 // 3. Cache miss, we need to parse the page. | |
| 52 if (wasPageVisitedRecently(url)) { | |
| 53 if (lastPageVisitContainedEntity(url)) { | |
| 54 // Condition 1 | |
| 55 getAppIndexingReporter().reportWebPageView(url, tab.getTitle()); | |
| 56 } | |
| 57 // Condition 2 | |
| 58 } else { | |
| 59 // Condition 3 | |
| 60 CopylessPaste copylessPaste = getCopylessPasteInterface(tab); | |
| 61 if (copylessPaste == null) { | |
| 62 return; | |
| 63 } | |
| 64 copylessPaste.getEntities(new CopylessPaste.GetEntitiesResponse() { | |
| 65 @Override | |
| 66 public void call(WebPage webpage) { | |
| 67 putCacheEntry(url, webpage != null); | |
| 68 if (webpage == null) return; | |
| 69 getAppIndexingReporter().reportWebPage(webpage); | |
| 70 } | |
| 71 }); | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 private boolean wasPageVisitedRecently(String url) { | |
| 76 if (url == null) { | |
| 77 return false; | |
| 78 } | |
| 79 CacheEntry entry = mPageCache.get(url); | |
| 80 if (entry == null || getElapsedTime() - entry.lastSeenTimeMs > CACHE_VIS IT_CUTOFF_MS) { | |
| 81 return false; | |
| 82 } | |
| 83 return true; | |
| 84 } | |
| 85 | |
| 86 // Returns true if the page is in the cache and it contained an entity the l ast time it was | |
| 87 // visited. | |
|
wychen
2017/04/13 07:05:00
it was *parsed*
dproctor
2017/04/13 17:23:09
Done.
| |
| 88 private boolean lastPageVisitContainedEntity(String url) { | |
| 89 if (url == null) { | |
| 90 return false; | |
| 91 } | |
| 92 CacheEntry entry = mPageCache.get(url); | |
| 93 if (entry == null || !entry.containedEntity) { | |
| 94 return false; | |
| 95 } | |
| 96 return true; | |
| 97 } | |
| 98 | |
| 99 private void putCacheEntry(String url, boolean containedEntity) { | |
| 100 CacheEntry entry = new CacheEntry(); | |
| 101 entry.lastSeenTimeMs = getElapsedTime(); | |
| 102 entry.containedEntity = containedEntity; | |
| 103 mPageCache.put(url, entry); | |
| 104 } | |
| 105 | |
| 106 @VisibleForTesting | |
| 107 AppIndexingReporter getAppIndexingReporter() { | |
| 108 return AppIndexingReporter.getInstance(); | |
| 109 } | |
| 110 | |
| 111 @VisibleForTesting | |
| 112 CopylessPaste getCopylessPasteInterface(Tab tab) { | |
| 31 WebContents webContents = tab.getWebContents(); | 113 WebContents webContents = tab.getWebContents(); |
| 32 if (webContents == null) return; | 114 if (webContents == null) return null; |
| 33 | 115 |
| 34 RenderFrameHost mainFrame = webContents.getMainFrame(); | 116 RenderFrameHost mainFrame = webContents.getMainFrame(); |
| 35 if (mainFrame == null) return; | 117 if (mainFrame == null) return null; |
| 36 | 118 |
| 37 InterfaceProvider interfaces = mainFrame.getRemoteInterfaces(); | 119 InterfaceProvider interfaces = mainFrame.getRemoteInterfaces(); |
| 38 if (interfaces == null) return; | 120 if (interfaces == null) return null; |
| 39 | 121 |
| 40 CopylessPaste copylesspaste = interfaces.getInterface(CopylessPaste.MANA GER); | 122 return interfaces.getInterface(CopylessPaste.MANAGER); |
| 41 copylesspaste.getEntities(new CopylessPaste.GetEntitiesResponse() { | 123 } |
| 42 @Override | 124 |
| 43 public void call(WebPage webpage) { | 125 @VisibleForTesting |
| 44 if (webpage == null) return; | 126 long getElapsedTime() { |
| 45 AppIndexingReporter.getInstance().reportWebPage(webpage); | 127 return SystemClock.elapsedRealtime(); |
| 46 } | 128 } |
| 47 }); | 129 |
| 130 boolean isEnabledForDevice() { | |
| 131 return !SysUtils.isLowEndDevice() | |
| 132 && ChromeFeatureList.isEnabled(ChromeFeatureList.COPYLESS_PASTE) ; | |
| 133 } | |
| 134 | |
| 135 private static class CacheEntry { | |
| 136 public long lastSeenTimeMs; | |
| 137 public boolean containedEntity; | |
| 48 } | 138 } |
| 49 } | 139 } |
| OLD | NEW |