Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java

Issue 2435383002: Update WebAPKs even if the WebAPK start URL has no Web Manifest part 1/3 (Closed)
Patch Set: Merge branch 'master' into update_fail0 Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 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.webapps; 5 package org.chromium.chrome.browser.webapps;
6 6
7 import android.content.pm.PackageInfo; 7 import android.content.pm.PackageInfo;
8 import android.content.pm.PackageManager; 8 import android.content.pm.PackageManager;
9 import android.graphics.Bitmap; 9 import android.graphics.Bitmap;
10 import android.os.Bundle;
11 10
12 import org.chromium.base.CommandLine; 11 import org.chromium.base.CommandLine;
13 import org.chromium.base.ContextUtils; 12 import org.chromium.base.ContextUtils;
14 import org.chromium.base.Log; 13 import org.chromium.base.Log;
15 import org.chromium.base.annotations.CalledByNative; 14 import org.chromium.base.annotations.CalledByNative;
16 import org.chromium.chrome.browser.ChromeSwitches; 15 import org.chromium.chrome.browser.ChromeSwitches;
17 import org.chromium.chrome.browser.tab.Tab; 16 import org.chromium.chrome.browser.tab.Tab;
18 import org.chromium.chrome.browser.util.IntentUtils;
19 import org.chromium.webapk.lib.client.WebApkVersion; 17 import org.chromium.webapk.lib.client.WebApkVersion;
20 import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
21 18
22 import java.util.concurrent.TimeUnit; 19 import java.util.concurrent.TimeUnit;
23 20
24 /** 21 /**
25 * WebApkUpdateManager manages when to check for updates to the WebAPK's Web Man ifest, and sends 22 * WebApkUpdateManager manages when to check for updates to the WebAPK's Web Man ifest, and sends
26 * an update request to the WebAPK Server when an update is needed. 23 * an update request to the WebAPK Server when an update is needed.
27 */ 24 */
28 public class WebApkUpdateManager implements ManifestUpgradeDetector.Callback { 25 public class WebApkUpdateManager implements ManifestUpgradeDetector.Callback {
29 private static final String TAG = "WebApkUpdateManager"; 26 private static final String TAG = "WebApkUpdateManager";
30 27
31 /** Number of milliseconds between checks for whether the WebAPK's Web Manif est has changed. */ 28 /** Number of milliseconds between checks for whether the WebAPK's Web Manif est has changed. */
32 public static final long FULL_CHECK_UPDATE_INTERVAL = TimeUnit.DAYS.toMillis (3L); 29 public static final long FULL_CHECK_UPDATE_INTERVAL = TimeUnit.DAYS.toMillis (3L);
33 30
34 /** 31 /**
35 * Number of milliseconds to wait before re-requesting an updated WebAPK fro m the WebAPK 32 * Number of milliseconds to wait before re-requesting an updated WebAPK fro m the WebAPK
36 * server if the previous update attempt failed. 33 * server if the previous update attempt failed.
37 */ 34 */
38 public static final long RETRY_UPDATE_DURATION = TimeUnit.HOURS.toMillis(12L ); 35 public static final long RETRY_UPDATE_DURATION = TimeUnit.HOURS.toMillis(12L );
39 36
40 /** 37 /** Id of WebAPK data in WebappDataStorage */
41 * Id of WebAPK data in WebappDataStorage
42 */
43 private String mId; 38 private String mId;
44 39
45 /** Android version code of WebAPK. */ 40 /** WebAPK package name. */
46 private int mVersionCode; 41 private String mWebApkPackageName;
42
43 /** Meta data from the WebAPK's Android Manifest */
44 private WebApkMetaData mMetaData;
45
46 /** WebAPK's icon. */
47 private Bitmap mIcon;
47 48
48 /** 49 /**
49 * Whether the previous WebAPK update succeeded. True if there has not been any update attempts. 50 * Whether the previous WebAPK update succeeded. True if there has not been any update attempts.
50 */ 51 */
51 private boolean mPreviousUpdateSucceeded; 52 private boolean mPreviousUpdateSucceeded;
52 53
53 private ManifestUpgradeDetector mUpgradeDetector; 54 private ManifestUpgradeDetector mUpgradeDetector;
54 55
55 /** 56 /**
56 * Checks whether the WebAPK's Web Manifest has changed. Requests an updated WebAPK if the 57 * Checks whether the WebAPK's Web Manifest has changed. Requests an updated WebAPK if the
57 * Web Manifest has changed. Skips the check if the check was done recently. 58 * Web Manifest has changed. Skips the check if the check was done recently.
58 * @param tab The tab of the WebAPK. 59 * @param tab The tab of the WebAPK.
59 * @param info The WebappInfo of the WebAPK. 60 * @param info The WebappInfo of the WebAPK.
60 */ 61 */
61 public void updateIfNeeded(Tab tab, WebappInfo info) { 62 public void updateIfNeeded(Tab tab, WebappInfo info) {
62 PackageInfo packageInfo = readPackageInfoFromAndroidManifest(info.webApk PackageName()); 63 mMetaData = WebApkMetaDataUtils.extractMetaDataFromWebApk(info.webApkPac kageName());
63 if (packageInfo == null) { 64 if (mMetaData == null) {
dominickn 2016/10/24 11:34:59 Nit: inline the return.
64 return; 65 return;
65 } 66 }
66 67
68 mWebApkPackageName = info.webApkPackageName();
67 mId = info.id(); 69 mId = info.id();
68 mVersionCode = packageInfo.versionCode; 70 mIcon = info.icon();
69 final Bundle metadata = packageInfo.applicationInfo.metaData;
70 int shellApkVersion =
71 IntentUtils.safeGetInt(metadata, WebApkMetaDataKeys.SHELL_APK_VE RSION, 0);
72 71
73 WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataSt orage(mId); 72 WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataSt orage(mId);
74 mPreviousUpdateSucceeded = didPreviousUpdateSucceed(storage); 73 mPreviousUpdateSucceeded = didPreviousUpdateSucceed(storage);
75 74
76 // TODO(pkotwicz|hanxi): Request upgrade if ShellAPK version changes if 75 if (!shouldCheckIfWebManifestUpdated(storage, mMetaData, mPreviousUpdate Succeeded)) return;
77 // ManifestUpgradeDetector cannot fetch the Web Manifest. For instance, the web developer
78 // may have removed the Web Manifest from their site. (http://crbug.com/ 639536)
79 76
80 if (!shouldCheckIfWebManifestUpdated(storage, shellApkVersion, mPrevious UpdateSucceeded)) { 77 mUpgradeDetector = buildManifestUpgradeDetector(tab, mMetaData);
81 return;
82 }
83
84 mUpgradeDetector = buildManifestUpgradeDetector(tab, info, metadata);
85 if (!mUpgradeDetector.start()) return; 78 if (!mUpgradeDetector.start()) return;
86 79
87 // crbug.com/636525. The timestamp of the last manifest update check sho uld be updated after 80 // crbug.com/636525. The timestamp of the last manifest update check sho uld be updated after
88 // the detector finds the manifest, not when the detector is started. 81 // the detector finds the manifest, not when the detector is started.
89 storage.updateTimeOfLastCheckForUpdatedWebManifest(); 82 storage.updateTimeOfLastCheckForUpdatedWebManifest();
90 } 83 }
91 84
85 public void destroy() {
dominickn 2016/10/24 11:34:59 Can you just override this method in tests, and ca
pkotwicz 2016/10/24 16:03:43 I made destroyUpgradeDetector() its own function t
dominickn 2016/10/25 07:39:16 The semantic difference doesn't really make sense
pkotwicz 2016/10/26 01:53:29 I think that the semantic difference makes sense i
86 destroyUpgradeDetector();
87 }
88
92 @Override 89 @Override
93 public void onUpgradeNeededCheckFinished(boolean needsUpgrade, 90 public void onFinishedFetchingWebManifestForInitialUrl(
94 ManifestUpgradeDetector.FetchedManifestData data) { 91 boolean needsUpgrade, ManifestUpgradeDetector.FetchedManifestData da ta) {
95 if (mUpgradeDetector != null) { 92 onGotManifestData(needsUpgrade, data);
96 mUpgradeDetector.destroy(); 93 }
94
95 @Override
96 public void onGotManifestData(
97 boolean needsUpgrade, ManifestUpgradeDetector.FetchedManifestData da ta) {
98 boolean gotManifest = (data != null);
99 needsUpgrade |= isShellApkVersionOutOfDate(mMetaData);
100 Log.v(TAG, "Got Manifest: " + gotManifest);
101 Log.v(TAG, "WebAPK upgrade needed: " + needsUpgrade);
102
103 // If the Web Manifest was not found and an upgrade is requested, stop f etching Web
104 // Manifests as the user navigates to avoid sending multiple WebAPK upda te requests. In
105 // particular:
106 // - A WebAPK update request on the initial load because the Shell APK v ersion is out of
107 // date.
108 // - A second WebAPK update request once the user navigates to a page wh ich points to the
109 // correct Web Manifest URL because the Web Manifest has been updated by the Web
110 // developer.
111 //
112 // If the Web Manifest was not found and an upgrade is not requested, ke ep on fetching
113 // Web Manifests as the user navigates. For instance, the WebAPK's start _url might not
114 // point to a Web Manifest because start_url redirects to the WebAPK's m ain page.
115 if (gotManifest || needsUpgrade) {
116 destroyUpgradeDetector();
97 } 117 }
98 mUpgradeDetector = null;
99
100 Log.v(TAG, "WebAPK upgrade needed: " + needsUpgrade);
101 118
102 if (!needsUpgrade) { 119 if (!needsUpgrade) {
103 if (!mPreviousUpdateSucceeded) { 120 if (!mPreviousUpdateSucceeded) {
104 recordUpdateInWebappDataStorage(mId, true); 121 recordUpdateInWebappDataStorage(mId, true);
105 } 122 }
106 return; 123 return;
107 } 124 }
108 125
109 // Set WebAPK update as having failed in case that Chrome is killed prio r to 126 // Set WebAPK update as having failed in case that Chrome is killed prio r to
110 // {@link onBuiltWebApk} being called. 127 // {@link onBuiltWebApk} being called.
111 recordUpdateInWebappDataStorage(mId, false); 128 recordUpdateInWebappDataStorage(mId, false);
112 updateAsync(data); 129
130 if (data != null) {
131 updateAsync(data.startUrl, data.scopeUrl, data.name, data.shortName, data.iconUrl,
132 data.iconMurmur2Hash, data.icon, data.displayMode, data.orie ntation,
133 data.themeColor, data.backgroundColor);
134 return;
135 }
136
137 updateAsyncUsingAndroidManifestMetaData();
113 } 138 }
114 139
115 /** 140 /**
116 * Builds {@link ManifestUpgradeDetector}. In a separate function for the sa ke of tests. 141 * Builds {@link ManifestUpgradeDetector}. In a separate function for the sa ke of tests.
117 */ 142 */
118 protected ManifestUpgradeDetector buildManifestUpgradeDetector( 143 protected ManifestUpgradeDetector buildManifestUpgradeDetector(
119 Tab tab, WebappInfo info, Bundle metaData) { 144 Tab tab, WebApkMetaData metaData) {
120 return new ManifestUpgradeDetector(tab, info, metaData, this); 145 return new ManifestUpgradeDetector(tab, metaData, this);
146 }
147
148 /**
149 * Sends a request to WebAPK Server to update WebAPK using the meta data fro m the WebAPK's
150 * Android Manifest.
151 */
152 private void updateAsyncUsingAndroidManifestMetaData() {
153 updateAsync(mMetaData.startUrl, mMetaData.scope, mMetaData.name, mMetaDa ta.shortName,
154 mMetaData.iconUrl, mMetaData.iconMurmur2Hash, mIcon, mMetaData.d isplayMode,
155 mMetaData.orientation, mMetaData.themeColor, mMetaData.backgroun dColor);
121 } 156 }
122 157
123 /** 158 /**
124 * Sends request to WebAPK Server to update WebAPK. 159 * Sends request to WebAPK Server to update WebAPK.
125 */ 160 */
126 public void updateAsync(ManifestUpgradeDetector.FetchedManifestData data) { 161 protected void updateAsync(String startUrl, String scopeUrl, String name, St ring shortName,
127 String packageName = mUpgradeDetector.getWebApkPackageName(); 162 String iconUrl, String iconMurmur2Hash, Bitmap icon, int displayMode , int orientation,
128 nativeUpdateAsync(mId, data.startUrl, data.scopeUrl, data.name, data.sho rtName, 163 long themeColor, long backgroundColor) {
129 data.iconUrl, data.iconMurmur2Hash, data.icon, data.displayMode, data.orientation, 164 int versionCode = readVersionCodeFromAndroidManifest(mWebApkPackageName) ;
130 data.themeColor, data.backgroundColor, mUpgradeDetector.getManif estUrl(), 165 nativeUpdateAsync(mId, startUrl, scopeUrl, name, shortName, iconUrl, ico nMurmur2Hash, icon,
131 packageName, mVersionCode); 166 displayMode, orientation, themeColor, backgroundColor, mMetaData .manifestUrl,
167 mWebApkPackageName, versionCode);
132 } 168 }
133 169
134 public void destroy() { 170 /**
135 if (mUpgradeDetector != null) { 171 * Destroys {@link mUpgradeDetector}. In a separate function for the sake of tests.
136 mUpgradeDetector.destroy(); 172 */
137 } 173 protected void destroyUpgradeDetector() {
174 if (mUpgradeDetector == null) return;
175
176 mUpgradeDetector.destroy();
138 mUpgradeDetector = null; 177 mUpgradeDetector = null;
139 } 178 }
140 179
141 /** Returns the current time. In a separate function for the sake of testing . */ 180 /** Returns the current time. In a separate function for the sake of testing . */
142 protected long currentTimeMillis() { 181 protected long currentTimeMillis() {
143 return System.currentTimeMillis(); 182 return System.currentTimeMillis();
144 } 183 }
145 184
146 /** 185 /**
147 * Reads the WebAPK's PackageInfo from the Android Manifest. 186 * Reads the WebAPK's version code. Returns 0 on failure.
148 */ 187 */
149 private PackageInfo readPackageInfoFromAndroidManifest(String webApkPackage) { 188 private int readVersionCodeFromAndroidManifest(String webApkPackage) {
150 try { 189 try {
151 PackageManager packageManager = 190 PackageManager packageManager =
152 ContextUtils.getApplicationContext().getPackageManager(); 191 ContextUtils.getApplicationContext().getPackageManager();
153 return packageManager.getPackageInfo(webApkPackage, PackageManager.G ET_META_DATA); 192 PackageInfo packageInfo = packageManager.getPackageInfo(webApkPackag e, 0);
193 return packageInfo.versionCode;
154 } catch (PackageManager.NameNotFoundException e) { 194 } catch (PackageManager.NameNotFoundException e) {
155 e.printStackTrace(); 195 e.printStackTrace();
156 } 196 }
157 return null; 197 return 0;
158 } 198 }
159 199
160 /** 200 /**
161 * Returns whether the previous WebAPK update attempt succeeded. Returns tru e if there has not 201 * Returns whether the previous WebAPK update attempt succeeded. Returns tru e if there has not
162 * been any update attempts. 202 * been any update attempts.
163 */ 203 */
164 private static boolean didPreviousUpdateSucceed(WebappDataStorage storage) { 204 private static boolean didPreviousUpdateSucceed(WebappDataStorage storage) {
165 long lastUpdateCompletionTime = storage.getLastWebApkUpdateRequestComple tionTime(); 205 long lastUpdateCompletionTime = storage.getLastWebApkUpdateRequestComple tionTime();
166 if (lastUpdateCompletionTime == WebappDataStorage.LAST_USED_INVALID 206 if (lastUpdateCompletionTime == WebappDataStorage.LAST_USED_INVALID
167 || lastUpdateCompletionTime == WebappDataStorage.LAST_USED_UNSET ) { 207 || lastUpdateCompletionTime == WebappDataStorage.LAST_USED_UNSET ) {
168 return true; 208 return true;
169 } 209 }
170 return storage.getDidLastWebApkUpdateRequestSucceed(); 210 return storage.getDidLastWebApkUpdateRequestSucceed();
171 } 211 }
172 212
173 /** 213 /**
214 * Whether there is a new version of the //chrome/android/webapk/shell_apk c ode.
215 */
216 private static boolean isShellApkVersionOutOfDate(WebApkMetaData metaData) {
217 return metaData.shellApkVersion < WebApkVersion.CURRENT_SHELL_APK_VERSIO N;
218 }
219
220 /**
174 * Returns whether the Web Manifest should be refetched to check whether it has been updated. 221 * Returns whether the Web Manifest should be refetched to check whether it has been updated.
175 * TODO: Make this method static once there is a static global clock class. 222 * TODO: Make this method static once there is a static global clock class.
176 * @param storage WebappDataStorage with the WebAPK's cached data. 223 * @param storage WebappDataStorage with the WebAPK's cached data.
177 * @param shellApkVersion Version number of //chrome/android/webapk/shell_ap k code. 224 * @param metaData Meta data from WebAPK's Android Manifest.
178 * @param previousUpdateSucceeded Whether the previous update attempt succee ded. 225 * @param previousUpdateSucceeded Whether the previous update attempt succee ded.
179 * True if there has not been any update attempts. 226 * True if there has not been any update attempts.
180 */ 227 */
181 private boolean shouldCheckIfWebManifestUpdated( 228 private boolean shouldCheckIfWebManifestUpdated(
182 WebappDataStorage storage, int shellApkVersion, boolean previousUpda teSucceeded) { 229 WebappDataStorage storage, WebApkMetaData metaData, boolean previous UpdateSucceeded) {
183 if (CommandLine.getInstance().hasSwitch( 230 if (CommandLine.getInstance().hasSwitch(
184 ChromeSwitches.CHECK_FOR_WEB_MANIFEST_UPDATE_ON_STARTUP)) { 231 ChromeSwitches.CHECK_FOR_WEB_MANIFEST_UPDATE_ON_STARTUP)) {
185 return true; 232 return true;
186 } 233 }
187 234
188 if (shellApkVersion < WebApkVersion.CURRENT_SHELL_APK_VERSION) return tr ue; 235 if (isShellApkVersionOutOfDate(metaData)) return true;
189 236
190 long now = currentTimeMillis(); 237 long now = currentTimeMillis();
191 long sinceLastCheckDurationMs = now - storage.getLastCheckForWebManifest UpdateTime(); 238 long sinceLastCheckDurationMs = now - storage.getLastCheckForWebManifest UpdateTime();
192 if (sinceLastCheckDurationMs >= FULL_CHECK_UPDATE_INTERVAL) return true; 239 if (sinceLastCheckDurationMs >= FULL_CHECK_UPDATE_INTERVAL) return true;
193 240
194 long sinceLastUpdateRequestDurationMs = 241 long sinceLastUpdateRequestDurationMs =
195 now - storage.getLastWebApkUpdateRequestCompletionTime(); 242 now - storage.getLastWebApkUpdateRequestCompletionTime();
196 return sinceLastUpdateRequestDurationMs >= RETRY_UPDATE_DURATION 243 return sinceLastUpdateRequestDurationMs >= RETRY_UPDATE_DURATION
197 && !previousUpdateSucceeded; 244 && !previousUpdateSucceeded;
198 } 245 }
(...skipping 17 matching lines...) Expand all
216 @CalledByNative 263 @CalledByNative
217 private static void onBuiltWebApk(String id, boolean success) { 264 private static void onBuiltWebApk(String id, boolean success) {
218 recordUpdateInWebappDataStorage(id, success); 265 recordUpdateInWebappDataStorage(id, success);
219 } 266 }
220 267
221 private static native void nativeUpdateAsync(String id, String startUrl, Str ing scope, 268 private static native void nativeUpdateAsync(String id, String startUrl, Str ing scope,
222 String name, String shortName, String iconUrl, String iconMurmur2Has h, Bitmap icon, 269 String name, String shortName, String iconUrl, String iconMurmur2Has h, Bitmap icon,
223 int displayMode, int orientation, long themeColor, long backgroundCo lor, 270 int displayMode, int orientation, long themeColor, long backgroundCo lor,
224 String manifestUrl, String webApkPackage, int webApkVersion); 271 String manifestUrl, String webApkPackage, int webApkVersion);
225 } 272 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698