OLD | NEW |
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 #include "chrome/browser/android/webapk/webapk_installer.h" | 5 #include "chrome/browser/android/webapk/webapk_installer.h" |
6 | 6 |
7 #include "base/android/build_info.h" | 7 #include "base/android/build_info.h" |
8 #include "base/android/jni_android.h" | 8 #include "base/android/jni_android.h" |
9 #include "base/android/jni_string.h" | 9 #include "base/android/jni_string.h" |
10 #include "base/android/path_utils.h" | 10 #include "base/android/path_utils.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include "jni/WebApkInstaller_jni.h" | 29 #include "jni/WebApkInstaller_jni.h" |
30 #include "net/http/http_status_code.h" | 30 #include "net/http/http_status_code.h" |
31 #include "net/url_request/url_fetcher.h" | 31 #include "net/url_request/url_fetcher.h" |
32 #include "ui/gfx/codec/png_codec.h" | 32 #include "ui/gfx/codec/png_codec.h" |
33 #include "url/gurl.h" | 33 #include "url/gurl.h" |
34 | 34 |
35 namespace { | 35 namespace { |
36 | 36 |
37 // The default WebAPK server URL. | 37 // The default WebAPK server URL. |
38 const char kDefaultWebApkServerUrl[] = | 38 const char kDefaultWebApkServerUrl[] = |
39 "https://webapk.googleapis.com/v1alpha/webApks?alt=proto"; | 39 "https://webapk.googleapis.com/v1alpha/webApks/"; |
| 40 |
| 41 // The response format type expected from the WebAPK server. |
| 42 const char kDefaultWebApkServerUrlResponseType[] = "?alt=proto"; |
40 | 43 |
41 // The MIME type of the POST data sent to the server. | 44 // The MIME type of the POST data sent to the server. |
42 const char kProtoMimeType[] = "application/x-protobuf"; | 45 const char kProtoMimeType[] = "application/x-protobuf"; |
43 | 46 |
44 // The default number of milliseconds to wait for the WebAPK download URL from | 47 // The default number of milliseconds to wait for the WebAPK download URL from |
45 // the WebAPK server. | 48 // the WebAPK server. |
46 const int kWebApkDownloadUrlTimeoutMs = 60000; | 49 const int kWebApkDownloadUrlTimeoutMs = 60000; |
47 | 50 |
48 // The default number of milliseconds to wait for the WebAPK download to | 51 // The default number of milliseconds to wait for the WebAPK download to |
49 // complete. | 52 // complete. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 return webapk; | 114 return webapk; |
112 } | 115 } |
113 | 116 |
114 // Returns task runner for running background tasks. | 117 // Returns task runner for running background tasks. |
115 scoped_refptr<base::TaskRunner> GetBackgroundTaskRunner() { | 118 scoped_refptr<base::TaskRunner> GetBackgroundTaskRunner() { |
116 return content::BrowserThread::GetBlockingPool() | 119 return content::BrowserThread::GetBlockingPool() |
117 ->GetTaskRunnerWithShutdownBehavior( | 120 ->GetTaskRunnerWithShutdownBehavior( |
118 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 121 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
119 } | 122 } |
120 | 123 |
| 124 GURL GetServerUrlForUpdate(const GURL& server_url, |
| 125 const std::string& webapk_package) { |
| 126 // crbug.com/636552. Simplify the server URL. |
| 127 return GURL(server_url.spec() + webapk_package + "/" + |
| 128 kDefaultWebApkServerUrlResponseType); |
| 129 } |
| 130 |
121 } // anonymous namespace | 131 } // anonymous namespace |
122 | 132 |
123 WebApkInstaller::WebApkInstaller(const ShortcutInfo& shortcut_info, | 133 WebApkInstaller::WebApkInstaller(const ShortcutInfo& shortcut_info, |
124 const SkBitmap& shortcut_icon) | 134 const SkBitmap& shortcut_icon) |
125 : shortcut_info_(shortcut_info), | 135 : shortcut_info_(shortcut_info), |
126 shortcut_icon_(shortcut_icon), | 136 shortcut_icon_(shortcut_icon), |
127 webapk_download_url_timeout_ms_(kWebApkDownloadUrlTimeoutMs), | 137 webapk_download_url_timeout_ms_(kWebApkDownloadUrlTimeoutMs), |
128 download_timeout_ms_(kDownloadTimeoutMs), | 138 download_timeout_ms_(kDownloadTimeoutMs), |
| 139 task_type_(UNDEFINED), |
129 weak_ptr_factory_(this) { | 140 weak_ptr_factory_(this) { |
130 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 141 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
131 server_url_ = | 142 server_url_ = |
132 GURL(command_line->HasSwitch(switches::kWebApkServerUrl) | 143 GURL(command_line->HasSwitch(switches::kWebApkServerUrl) |
133 ? command_line->GetSwitchValueASCII(switches::kWebApkServerUrl) | 144 ? command_line->GetSwitchValueASCII(switches::kWebApkServerUrl) |
134 : kDefaultWebApkServerUrl); | 145 : kDefaultWebApkServerUrl); |
135 } | 146 } |
136 | 147 |
137 WebApkInstaller::~WebApkInstaller() {} | 148 WebApkInstaller::~WebApkInstaller() {} |
138 | 149 |
139 void WebApkInstaller::InstallAsync(content::BrowserContext* browser_context, | 150 void WebApkInstaller::InstallAsync(content::BrowserContext* browser_context, |
140 const FinishCallback& finish_callback) { | 151 const FinishCallback& finish_callback) { |
141 InstallAsyncWithURLRequestContextGetter( | 152 InstallAsyncWithURLRequestContextGetter( |
142 Profile::FromBrowserContext(browser_context)->GetRequestContext(), | 153 Profile::FromBrowserContext(browser_context)->GetRequestContext(), |
143 finish_callback); | 154 finish_callback); |
144 } | 155 } |
145 | 156 |
146 void WebApkInstaller::InstallAsyncWithURLRequestContextGetter( | 157 void WebApkInstaller::InstallAsyncWithURLRequestContextGetter( |
147 net::URLRequestContextGetter* request_context_getter, | 158 net::URLRequestContextGetter* request_context_getter, |
148 const FinishCallback& finish_callback) { | 159 const FinishCallback& finish_callback) { |
149 request_context_getter_ = request_context_getter; | 160 request_context_getter_ = request_context_getter; |
150 finish_callback_ = finish_callback; | 161 finish_callback_ = finish_callback; |
| 162 task_type_ = INSTALL; |
151 | 163 |
152 if (!shortcut_info_.icon_url.is_valid()) { | 164 if (!shortcut_info_.icon_url.is_valid()) { |
153 OnFailure(); | 165 OnFailure(); |
154 return; | 166 return; |
155 } | 167 } |
156 | 168 |
157 // We need to take the hash of the bitmap at the icon URL prior to any | 169 // We need to take the hash of the bitmap at the icon URL prior to any |
158 // transformations being applied to the bitmap (such as encoding/decoding | 170 // transformations being applied to the bitmap (such as encoding/decoding |
159 // the bitmap). The icon hash is used to determine whether the icon that | 171 // the bitmap). The icon hash is used to determine whether the icon that |
160 // the user sees matches the icon of a WebAPK that the WebAPK server | 172 // the user sees matches the icon of a WebAPK that the WebAPK server |
161 // generated for another user. (The icon can be dynamically generated.) | 173 // generated for another user. (The icon can be dynamically generated.) |
162 // | 174 // |
163 // We redownload the icon in order to take the Murmur2 hash. The redownload | 175 // We redownload the icon in order to take the Murmur2 hash. The redownload |
164 // should be fast because the icon should be in the HTTP cache. | 176 // should be fast because the icon should be in the HTTP cache. |
165 DownloadAppIconAndComputeMurmur2Hash(); | 177 DownloadAppIconAndComputeMurmur2Hash(); |
166 } | 178 } |
167 | 179 |
168 void WebApkInstaller::SetTimeoutMs(int timeout_ms) { | 180 void WebApkInstaller::SetTimeoutMs(int timeout_ms) { |
169 webapk_download_url_timeout_ms_ = timeout_ms; | 181 webapk_download_url_timeout_ms_ = timeout_ms; |
170 download_timeout_ms_ = timeout_ms; | 182 download_timeout_ms_ = timeout_ms; |
171 } | 183 } |
172 | 184 |
173 bool WebApkInstaller::StartDownloadedWebApkInstall( | 185 void WebApkInstaller::UpdateAsync(content::BrowserContext* browser_context, |
| 186 const FinishCallback& finish_callback, |
| 187 const std::string& webapk_package, |
| 188 int webapk_version) { |
| 189 UpdateAsyncWithURLRequestContextGetter( |
| 190 Profile::FromBrowserContext(browser_context)->GetRequestContext(), |
| 191 finish_callback, webapk_package, webapk_version); |
| 192 } |
| 193 |
| 194 void WebApkInstaller::UpdateAsyncWithURLRequestContextGetter( |
| 195 net::URLRequestContextGetter* request_context_getter, |
| 196 const FinishCallback& finish_callback, |
| 197 const std::string& webapk_package, |
| 198 int webapk_version) { |
| 199 request_context_getter_ = request_context_getter; |
| 200 finish_callback_ = finish_callback; |
| 201 webapk_package_ = webapk_package; |
| 202 webapk_version_ = webapk_version; |
| 203 task_type_ = UPDATE; |
| 204 |
| 205 if (!shortcut_info_.icon_url.is_valid()) { |
| 206 OnFailure(); |
| 207 return; |
| 208 } |
| 209 |
| 210 DownloadAppIconAndComputeMurmur2Hash(); |
| 211 } |
| 212 |
| 213 bool WebApkInstaller::StartInstallingDownloadedWebApk( |
174 JNIEnv* env, | 214 JNIEnv* env, |
175 const base::android::ScopedJavaLocalRef<jstring>& java_file_path, | 215 const base::android::ScopedJavaLocalRef<jstring>& java_file_path, |
176 const base::android::ScopedJavaLocalRef<jstring>& java_package_name) { | 216 const base::android::ScopedJavaLocalRef<jstring>& java_package_name) { |
177 return Java_WebApkInstaller_installAsyncFromNative(env, java_file_path, | 217 return Java_WebApkInstaller_installAsyncFromNative(env, java_file_path, |
178 java_package_name); | 218 java_package_name); |
179 } | 219 } |
180 | 220 |
| 221 bool WebApkInstaller::StartUpdateUsingDownloadedWebApk( |
| 222 JNIEnv* env, |
| 223 const base::android::ScopedJavaLocalRef<jstring>& java_file_path, |
| 224 const base::android::ScopedJavaLocalRef<jstring>& java_package_name) { |
| 225 return Java_WebApkInstaller_updateAsyncFromNative(env, java_file_path, |
| 226 java_package_name); |
| 227 } |
| 228 |
181 void WebApkInstaller::OnURLFetchComplete(const net::URLFetcher* source) { | 229 void WebApkInstaller::OnURLFetchComplete(const net::URLFetcher* source) { |
182 timer_.Stop(); | 230 timer_.Stop(); |
183 | 231 |
184 if (!source->GetStatus().is_success() || | 232 if (!source->GetStatus().is_success() || |
185 source->GetResponseCode() != net::HTTP_OK) { | 233 source->GetResponseCode() != net::HTTP_OK) { |
186 OnFailure(); | 234 OnFailure(); |
187 return; | 235 return; |
188 } | 236 } |
189 | 237 |
190 std::string response_string; | 238 std::string response_string; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 icon_hasher_.reset(); | 271 icon_hasher_.reset(); |
224 | 272 |
225 shortcut_icon_murmur2_hash_ = icon_murmur2_hash; | 273 shortcut_icon_murmur2_hash_ = icon_murmur2_hash; |
226 | 274 |
227 // An empty hash indicates that |icon_hasher_| encountered an error. | 275 // An empty hash indicates that |icon_hasher_| encountered an error. |
228 if (icon_murmur2_hash.empty()) { | 276 if (icon_murmur2_hash.empty()) { |
229 OnFailure(); | 277 OnFailure(); |
230 return; | 278 return; |
231 } | 279 } |
232 | 280 |
233 base::PostTaskAndReplyWithResult( | 281 if (task_type_ == INSTALL) { |
234 GetBackgroundTaskRunner().get(), FROM_HERE, | 282 base::PostTaskAndReplyWithResult( |
235 base::Bind(&BuildWebApkProtoInBackground, shortcut_info_, shortcut_icon_, | 283 GetBackgroundTaskRunner().get(), FROM_HERE, |
236 shortcut_icon_murmur2_hash_), | 284 base::Bind(&BuildWebApkProtoInBackground, shortcut_info_, |
237 base::Bind(&WebApkInstaller::SendCreateWebApkRequest, | 285 shortcut_icon_, shortcut_icon_murmur2_hash_), |
238 weak_ptr_factory_.GetWeakPtr())); | 286 base::Bind(&WebApkInstaller::SendCreateWebApkRequest, |
| 287 weak_ptr_factory_.GetWeakPtr())); |
| 288 } else if (task_type_ == UPDATE) { |
| 289 base::PostTaskAndReplyWithResult( |
| 290 GetBackgroundTaskRunner().get(), FROM_HERE, |
| 291 base::Bind(&BuildWebApkProtoInBackground, shortcut_info_, |
| 292 shortcut_icon_, shortcut_icon_murmur2_hash_), |
| 293 base::Bind(&WebApkInstaller::SendUpdateWebApkRequest, |
| 294 weak_ptr_factory_.GetWeakPtr())); |
| 295 } |
239 } | 296 } |
240 | 297 |
241 void WebApkInstaller::SendCreateWebApkRequest( | 298 void WebApkInstaller::SendCreateWebApkRequest( |
242 std::unique_ptr<webapk::WebApk> webapk_proto) { | 299 std::unique_ptr<webapk::WebApk> webapk) { |
| 300 GURL server_url(server_url_.spec() + kDefaultWebApkServerUrlResponseType); |
| 301 SendRequest(std::move(webapk), net::URLFetcher::POST, server_url); |
| 302 } |
| 303 |
| 304 void WebApkInstaller::SendUpdateWebApkRequest( |
| 305 std::unique_ptr<webapk::WebApk> webapk) { |
| 306 webapk->set_package_name(webapk_package_); |
| 307 webapk->set_version(std::to_string(webapk_version_)); |
| 308 |
| 309 SendRequest(std::move(webapk), net::URLFetcher::PUT, |
| 310 GetServerUrlForUpdate(server_url_, webapk_package_)); |
| 311 } |
| 312 |
| 313 void WebApkInstaller::SendRequest(std::unique_ptr<webapk::WebApk> request_proto, |
| 314 net::URLFetcher::RequestType request_type, |
| 315 const GURL& server_url) { |
243 timer_.Start( | 316 timer_.Start( |
244 FROM_HERE, | 317 FROM_HERE, |
245 base::TimeDelta::FromMilliseconds(webapk_download_url_timeout_ms_), | 318 base::TimeDelta::FromMilliseconds(webapk_download_url_timeout_ms_), |
246 base::Bind(&WebApkInstaller::OnTimeout, weak_ptr_factory_.GetWeakPtr())); | 319 base::Bind(&WebApkInstaller::OnTimeout, weak_ptr_factory_.GetWeakPtr())); |
247 | 320 |
248 url_fetcher_ = | 321 url_fetcher_ = net::URLFetcher::Create(server_url, request_type, this); |
249 net::URLFetcher::Create(server_url_, net::URLFetcher::POST, this); | |
250 url_fetcher_->SetRequestContext(request_context_getter_); | 322 url_fetcher_->SetRequestContext(request_context_getter_); |
251 std::string serialized_request; | 323 std::string serialized_request; |
252 webapk_proto->SerializeToString(&serialized_request); | 324 request_proto->SerializeToString(&serialized_request); |
253 url_fetcher_->SetUploadData(kProtoMimeType, serialized_request); | 325 url_fetcher_->SetUploadData(kProtoMimeType, serialized_request); |
254 url_fetcher_->Start(); | 326 url_fetcher_->Start(); |
255 } | 327 } |
256 | 328 |
257 void WebApkInstaller::OnGotWebApkDownloadUrl(const GURL& download_url, | 329 void WebApkInstaller::OnGotWebApkDownloadUrl(const GURL& download_url, |
258 const std::string& package_name) { | 330 const std::string& package_name) { |
259 base::FilePath output_dir; | 331 base::FilePath output_dir; |
260 base::android::GetCacheDirectory(&output_dir); | 332 base::android::GetCacheDirectory(&output_dir); |
261 // TODO(pkotwicz): Download WebAPKs into WebAPK-specific subdirectory | 333 // TODO(pkotwicz): Download WebAPKs into WebAPK-specific subdirectory |
262 // directory. | 334 // directory. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 if (!change_permission_success) { | 373 if (!change_permission_success) { |
302 OnFailure(); | 374 OnFailure(); |
303 return; | 375 return; |
304 } | 376 } |
305 | 377 |
306 JNIEnv* env = base::android::AttachCurrentThread(); | 378 JNIEnv* env = base::android::AttachCurrentThread(); |
307 base::android::ScopedJavaLocalRef<jstring> java_file_path = | 379 base::android::ScopedJavaLocalRef<jstring> java_file_path = |
308 base::android::ConvertUTF8ToJavaString(env, file_path.value()); | 380 base::android::ConvertUTF8ToJavaString(env, file_path.value()); |
309 base::android::ScopedJavaLocalRef<jstring> java_package_name = | 381 base::android::ScopedJavaLocalRef<jstring> java_package_name = |
310 base::android::ConvertUTF8ToJavaString(env, package_name); | 382 base::android::ConvertUTF8ToJavaString(env, package_name); |
311 bool success = | 383 bool success = false; |
312 StartDownloadedWebApkInstall(env, java_file_path, java_package_name); | 384 if (task_type_ == INSTALL) { |
| 385 success = StartInstallingDownloadedWebApk(env, java_file_path, |
| 386 java_package_name); |
| 387 } else if (task_type_ == UPDATE) { |
| 388 success = StartUpdateUsingDownloadedWebApk(env, java_file_path, |
| 389 java_package_name); |
| 390 } |
313 if (success) | 391 if (success) |
314 OnSuccess(); | 392 OnSuccess(); |
315 else | 393 else |
316 OnFailure(); | 394 OnFailure(); |
317 } | 395 } |
318 | 396 |
319 void WebApkInstaller::OnTimeout() { | 397 void WebApkInstaller::OnTimeout() { |
320 OnFailure(); | 398 OnFailure(); |
321 } | 399 } |
322 | 400 |
323 void WebApkInstaller::OnSuccess() { | 401 void WebApkInstaller::OnSuccess() { |
324 FinishCallback callback = finish_callback_; | 402 FinishCallback callback = finish_callback_; |
325 delete this; | 403 delete this; |
326 callback.Run(true); | 404 callback.Run(true); |
327 } | 405 } |
328 | 406 |
329 void WebApkInstaller::OnFailure() { | 407 void WebApkInstaller::OnFailure() { |
330 FinishCallback callback = finish_callback_; | 408 FinishCallback callback = finish_callback_; |
331 delete this; | 409 delete this; |
332 callback.Run(false); | 410 callback.Run(false); |
333 } | 411 } |
OLD | NEW |