Chromium Code Reviews| 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" |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
| 14 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
| 15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 18 #include "chrome/browser/android/shortcut_helper.h" | 18 #include "chrome/browser/android/shortcut_helper.h" |
| 19 #include "chrome/browser/android/webapk/webapk.pb.h" | 19 #include "chrome/browser/android/webapk/webapk.pb.h" |
| 20 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 21 #include "chrome/common/chrome_switches.h" | 21 #include "chrome/common/chrome_switches.h" |
| 22 #include "components/version_info/version_info.h" | 22 #include "components/version_info/version_info.h" |
| 23 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
| 24 #include "content/public/common/manifest_util.h" | 24 #include "content/public/common/manifest_util.h" |
| 25 #include "jni/WebApkInstaller_jni.h" | 25 #include "jni/WebApkInstaller_jni.h" |
| 26 #include "net/http/http_status_code.h" | 26 #include "net/http/http_status_code.h" |
| 27 #include "net/url_request/url_fetcher.h" | 27 #include "net/url_request/url_fetcher.h" |
| 28 #include "third_party/protobuf/src/google/protobuf/message_lite.h" | |
| 28 #include "third_party/smhasher/src/MurmurHash2.h" | 29 #include "third_party/smhasher/src/MurmurHash2.h" |
| 29 #include "ui/gfx/codec/png_codec.h" | 30 #include "ui/gfx/codec/png_codec.h" |
| 30 #include "url/gurl.h" | 31 #include "url/gurl.h" |
| 31 | 32 |
| 32 namespace { | 33 namespace { |
| 33 | 34 |
| 34 // The default WebAPK server URL. | 35 // The default WebAPK server URL. |
| 35 const char kDefaultWebApkServerUrl[] = | 36 const char kDefaultWebApkServerUrl[] = |
| 36 "https://webapk.googleapis.com/v1alpha/webApks?alt=proto"; | 37 "https://webapk.googleapis.com/v1alpha/webApks?alt=proto"; |
| 37 | 38 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 return RegisterNativesImpl(env); | 97 return RegisterNativesImpl(env); |
| 97 } | 98 } |
| 98 | 99 |
| 99 void WebApkInstaller::InstallAsync(content::BrowserContext* browser_context, | 100 void WebApkInstaller::InstallAsync(content::BrowserContext* browser_context, |
| 100 const FinishCallback& finish_callback) { | 101 const FinishCallback& finish_callback) { |
| 101 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 102 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 102 finish_callback_ = finish_callback; | 103 finish_callback_ = finish_callback; |
| 103 // base::Unretained() is safe because WebApkInstaller owns itself and does not | 104 // base::Unretained() is safe because WebApkInstaller owns itself and does not |
| 104 // start the timeout timer till after | 105 // start the timeout timer till after |
| 105 // InitializeRequestContextGetterOnUIThread() is called. | 106 // InitializeRequestContextGetterOnUIThread() is called. |
| 106 content::BrowserThread::PostTask( | 107 content::BrowserThread::PostTaskAndReply( |
| 107 content::BrowserThread::UI, FROM_HERE, | 108 content::BrowserThread::UI, FROM_HERE, |
| 108 base::Bind(&WebApkInstaller::InitializeRequestContextGetterOnUIThread, | 109 base::Bind(&WebApkInstaller::InitializeRequestContextGetterOnUIThread, |
| 109 base::Unretained(this), browser_context)); | 110 base::Unretained(this), browser_context), |
| 111 base::Bind(&WebApkInstaller::SendCreateWebApkRequest, | |
| 112 io_weak_ptr_factory_.GetWeakPtr())); | |
| 110 } | 113 } |
| 111 | 114 |
| 112 void WebApkInstaller::InstallAsyncWithURLRequestContextGetter( | 115 void WebApkInstaller::InstallAsyncWithURLRequestContextGetter( |
| 113 net::URLRequestContextGetter* request_context_getter, | 116 net::URLRequestContextGetter* request_context_getter, |
| 114 const FinishCallback& finish_callback) { | 117 const FinishCallback& finish_callback) { |
| 115 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 118 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 116 request_context_getter_ = request_context_getter; | 119 request_context_getter_ = request_context_getter; |
| 117 finish_callback_ = finish_callback; | 120 finish_callback_ = finish_callback; |
| 118 | 121 |
| 119 SendCreateWebApkRequest(); | 122 SendCreateWebApkRequest(); |
| 120 } | 123 } |
| 121 | 124 |
| 125 void WebApkInstaller::UpdateAsync(content::BrowserContext* browser_context, | |
| 126 const FinishCallback& finish_callback, | |
| 127 const std::string& webapk_package, | |
| 128 int version) { | |
| 129 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 130 finish_callback_ = finish_callback; | |
| 131 webapk_package_ = webapk_package; | |
| 132 version_ = version; | |
| 133 // base::Unretained() is safe because WebApkInstaller owns itself and does not | |
| 134 // start the timeout timer till after | |
| 135 // InitializeRequestContextGetterOnUIThread() is called. | |
| 136 content::BrowserThread::PostTaskAndReply( | |
| 137 content::BrowserThread::UI, FROM_HERE, | |
| 138 base::Bind(&WebApkInstaller::InitializeRequestContextGetterOnUIThread, | |
| 139 base::Unretained(this), browser_context), | |
| 140 base::Bind(&WebApkInstaller::SendUpdateWebApkRequest, | |
| 141 io_weak_ptr_factory_.GetWeakPtr())); | |
| 142 } | |
| 143 | |
| 122 bool WebApkInstaller::StartDownloadedWebApkInstall( | 144 bool WebApkInstaller::StartDownloadedWebApkInstall( |
| 123 JNIEnv* env, | 145 JNIEnv* env, |
| 124 const base::android::ScopedJavaLocalRef<jstring>& java_file_path, | 146 const base::android::ScopedJavaLocalRef<jstring>& java_file_path, |
| 125 const base::android::ScopedJavaLocalRef<jstring>& java_package_name) { | 147 const base::android::ScopedJavaLocalRef<jstring>& java_package_name) { |
|
pkotwicz
2016/08/03 22:03:16
While reading the design docs I realized that we n
| |
| 126 return Java_WebApkInstaller_installAsyncFromNative(env, java_file_path.obj(), | 148 return Java_WebApkInstaller_installAsyncFromNative(env, java_file_path.obj(), |
| 127 java_package_name.obj()); | 149 java_package_name.obj()); |
| 128 } | 150 } |
| 129 | 151 |
| 130 void WebApkInstaller::OnURLFetchComplete(const net::URLFetcher* source) { | 152 void WebApkInstaller::OnURLFetchComplete(const net::URLFetcher* source) { |
| 131 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 153 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 132 timer_.Stop(); | 154 timer_.Stop(); |
| 133 | 155 |
| 134 if (!source->GetStatus().is_success() || | 156 if (!source->GetStatus().is_success() || |
| 135 source->GetResponseCode() != net::HTTP_OK) { | 157 source->GetResponseCode() != net::HTTP_OK) { |
| 136 OnFailure(); | 158 OnFailure(); |
| 137 return; | 159 return; |
| 138 } | 160 } |
| 139 | 161 |
| 140 std::string response_string; | 162 std::string response_string; |
| 141 source->GetResponseAsString(&response_string); | 163 source->GetResponseAsString(&response_string); |
| 142 | 164 |
| 143 std::unique_ptr<webapk::CreateWebApkResponse> response( | 165 std::unique_ptr<webapk::WebApkResponse> response( |
| 144 new webapk::CreateWebApkResponse); | 166 new webapk::WebApkResponse); |
| 145 if (!response->ParseFromString(response_string)) { | 167 if (!response->ParseFromString(response_string)) { |
| 146 OnFailure(); | 168 OnFailure(); |
| 147 return; | 169 return; |
| 148 } | 170 } |
| 149 | 171 |
| 150 if (response->signed_download_url().empty() || | 172 if (response->signed_download_url().empty() || |
| 151 response->webapk_package_name().empty()) { | 173 response->webapk_package_name().empty()) { |
| 152 OnFailure(); | 174 OnFailure(); |
| 153 return; | 175 return; |
| 154 } | 176 } |
| 155 OnGotWebApkDownloadUrl(response->signed_download_url(), | 177 OnGotWebApkDownloadUrl(response->signed_download_url(), |
| 156 response->webapk_package_name()); | 178 response->webapk_package_name()); |
| 157 } | 179 } |
| 158 | 180 |
| 159 void WebApkInstaller::InitializeRequestContextGetterOnUIThread( | 181 void WebApkInstaller::InitializeRequestContextGetterOnUIThread( |
| 160 content::BrowserContext* browser_context) { | 182 content::BrowserContext* browser_context) { |
| 161 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 183 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 162 // Profile::GetRequestContext() must be called on UI thread. | 184 // Profile::GetRequestContext() must be called on UI thread. |
| 163 request_context_getter_ = | 185 request_context_getter_ = |
| 164 Profile::FromBrowserContext(browser_context)->GetRequestContext(); | 186 Profile::FromBrowserContext(browser_context)->GetRequestContext(); |
| 165 | |
| 166 content::BrowserThread::PostTask( | |
| 167 content::BrowserThread::IO, FROM_HERE, | |
| 168 base::Bind(&WebApkInstaller::SendCreateWebApkRequest, | |
| 169 io_weak_ptr_factory_.GetWeakPtr())); | |
| 170 } | 187 } |
| 171 | 188 |
| 172 void WebApkInstaller::SendCreateWebApkRequest() { | 189 void WebApkInstaller::SendCreateWebApkRequest() { |
| 173 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 190 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 174 std::unique_ptr<webapk::CreateWebApkRequest> request = | |
| 175 BuildCreateWebApkRequest(); | |
| 176 | 191 |
| 192 std::unique_ptr<webapk::CreateWebApkRequest> request | |
| 193 = std::unique_ptr<webapk::CreateWebApkRequest>( | |
| 194 new webapk::CreateWebApkRequest); | |
| 195 | |
| 196 PopulateWebApkProto(request->mutable_webapk()); | |
| 197 SendRequest(std::move(request)); | |
| 198 } | |
| 199 | |
| 200 void WebApkInstaller::SendUpdateWebApkRequest() { | |
| 201 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 202 | |
| 203 std::unique_ptr<webapk::UpdateWebApkRequest> request | |
| 204 = std::unique_ptr<webapk::UpdateWebApkRequest>( | |
| 205 new webapk::UpdateWebApkRequest); | |
| 206 | |
| 207 webapk::WebApk* webapk = request->mutable_webapk(); | |
| 208 PopulateWebApkProto(webapk); | |
| 209 webapk->set_package_name(webapk_package_); | |
| 210 webapk->set_version(std::to_string(version_)); | |
| 211 SendRequest(std::move(request)); | |
| 212 } | |
| 213 | |
| 214 void WebApkInstaller::SendRequest( | |
| 215 std::unique_ptr<::google::protobuf::MessageLite> request_proto) { | |
| 177 timer_.Start(FROM_HERE, | 216 timer_.Start(FROM_HERE, |
| 178 base::TimeDelta::FromMilliseconds(kWebApkDownloadUrlTimeoutMs), | 217 base::TimeDelta::FromMilliseconds(kWebApkDownloadUrlTimeoutMs), |
| 179 base::Bind(&WebApkInstaller::OnTimeout, | 218 base::Bind(&WebApkInstaller::OnTimeout, |
| 180 io_weak_ptr_factory_.GetWeakPtr())); | 219 io_weak_ptr_factory_.GetWeakPtr())); |
| 181 | 220 |
| 182 url_fetcher_ = | 221 url_fetcher_ = |
| 183 net::URLFetcher::Create(server_url_, net::URLFetcher::POST, this); | 222 net::URLFetcher::Create(server_url_, net::URLFetcher::POST, this); |
| 184 url_fetcher_->SetRequestContext(request_context_getter_); | 223 url_fetcher_->SetRequestContext(request_context_getter_); |
| 185 std::string serialized_request; | 224 std::string serialized_request; |
| 186 request->SerializeToString(&serialized_request); | 225 request_proto->SerializeToString(&serialized_request); |
| 187 url_fetcher_->SetUploadData(kProtoMimeType, serialized_request); | 226 url_fetcher_->SetUploadData(kProtoMimeType, serialized_request); |
| 188 url_fetcher_->Start(); | 227 url_fetcher_->Start(); |
| 189 } | 228 } |
| 190 | 229 |
| 191 void WebApkInstaller::OnGotWebApkDownloadUrl(const std::string& download_url, | 230 void WebApkInstaller::OnGotWebApkDownloadUrl(const std::string& download_url, |
| 192 const std::string& package_name) { | 231 const std::string& package_name) { |
| 193 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 232 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 194 | 233 |
| 195 base::FilePath output_dir; | 234 base::FilePath output_dir; |
| 196 base::android::GetCacheDirectory(&output_dir); | 235 base::android::GetCacheDirectory(&output_dir); |
| 197 // TODO(pkotwicz): Download WebAPKs into WebAPK-specific subdirectory | 236 // TODO(pkotwicz): Download WebAPKs into WebAPK-specific subdirectory |
| 198 // directory. | 237 // directory. |
| 199 // TODO(pkotwicz): Figure out when downloaded WebAPK should be deleted. | 238 // TODO(pkotwicz): Figure out when downloaded WebAPK should be deleted. |
| 200 | 239 |
| 201 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kDownloadTimeoutMs), | 240 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kDownloadTimeoutMs), |
| 202 base::Bind(&WebApkInstaller::OnTimeout, | 241 base::Bind(&WebApkInstaller::OnTimeout, |
| 203 io_weak_ptr_factory_.GetWeakPtr())); | 242 io_weak_ptr_factory_.GetWeakPtr())); |
| 204 | 243 |
| 205 base::FilePath output_path = output_dir.AppendASCII(package_name); | 244 base::FilePath output_path = output_dir.AppendASCII(package_name); |
| 206 downloader_.reset(new FileDownloader( | 245 downloader_.reset(new FileDownloader( |
| 207 GURL(download_url), output_path, true, request_context_getter_, | 246 GURL(download_url), output_path, true, request_context_getter_, |
| 208 base::Bind(&WebApkInstaller::OnWebApkDownloaded, | 247 base::Bind(&WebApkInstaller::OnWebApkDownloaded, |
| 209 io_weak_ptr_factory_.GetWeakPtr(), output_path, | 248 io_weak_ptr_factory_.GetWeakPtr(), output_path, |
| 210 package_name))); | 249 package_name))); |
| 211 } | 250 } |
| 212 | 251 |
| 213 void WebApkInstaller::OnWebApkDownloaded(const base::FilePath& file_path, | 252 void WebApkInstaller::OnWebApkDownloaded(const base::FilePath& file_path, |
| 214 const std::string& package_name, | 253 const std::string& package_name, |
| 215 FileDownloader::Result result) { | 254 FileDownloader::Result result) { |
| 216 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 255 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 217 | 256 |
| 218 timer_.Stop(); | 257 timer_.Stop(); |
| 219 | 258 |
| 220 if (result != FileDownloader::DOWNLOADED) { | 259 if (result != FileDownloader::DOWNLOADED) { |
| 221 OnFailure(); | 260 OnFailure(); |
| 222 return; | 261 return; |
| 223 } | 262 } |
| 224 | 263 |
| 225 JNIEnv* env = base::android::AttachCurrentThread(); | 264 JNIEnv* env = base::android::AttachCurrentThread(); |
| 226 base::android::ScopedJavaLocalRef<jstring> java_file_path = | 265 base::android::ScopedJavaLocalRef<jstring> java_file_path = |
| 227 base::android::ConvertUTF8ToJavaString(env, file_path.value()); | 266 base::android::ConvertUTF8ToJavaString(env, file_path.value()); |
| 228 base::android::ScopedJavaLocalRef<jstring> java_package_name = | 267 base::android::ScopedJavaLocalRef<jstring> java_package_name = |
| 229 base::android::ConvertUTF8ToJavaString(env, package_name); | 268 base::android::ConvertUTF8ToJavaString(env, package_name); |
| 230 bool success = | 269 bool success = |
| 231 StartDownloadedWebApkInstall(env, java_file_path, java_package_name); | 270 StartDownloadedWebApkInstall(env, java_file_path, java_package_name); |
| 232 if (success) | 271 if (success) |
| 233 OnSuccess(); | 272 OnSuccess(); |
| 234 else | 273 else |
| 235 OnFailure(); | 274 OnFailure(); |
| 236 } | 275 } |
| 237 | 276 |
| 238 std::unique_ptr<webapk::CreateWebApkRequest> | 277 void WebApkInstaller::PopulateWebApkProto(webapk::WebApk* webapk) { |
| 239 WebApkInstaller::BuildCreateWebApkRequest() { | |
| 240 std::unique_ptr<webapk::CreateWebApkRequest> request( | |
| 241 new webapk::CreateWebApkRequest); | |
| 242 | |
| 243 webapk::WebApk* webapk = request->mutable_webapk(); | |
| 244 webapk->set_manifest_url(shortcut_info_.manifest_url.spec()); | 278 webapk->set_manifest_url(shortcut_info_.manifest_url.spec()); |
| 245 webapk->set_requester_application_package( | 279 webapk->set_requester_application_package( |
| 246 base::android::BuildInfo::GetInstance()->package_name()); | 280 base::android::BuildInfo::GetInstance()->package_name()); |
| 247 webapk->set_requester_application_version(version_info::GetVersionNumber()); | 281 webapk->set_requester_application_version(version_info::GetVersionNumber()); |
| 248 | 282 |
| 249 webapk::WebAppManifest* web_app_manifest = webapk->mutable_manifest(); | 283 webapk::WebAppManifest* web_app_manifest = webapk->mutable_manifest(); |
| 250 web_app_manifest->set_name(base::UTF16ToUTF8(shortcut_info_.name)); | 284 web_app_manifest->set_name(base::UTF16ToUTF8(shortcut_info_.name)); |
| 251 web_app_manifest->set_short_name( | 285 web_app_manifest->set_short_name( |
| 252 base::UTF16ToUTF8(shortcut_info_.short_name)); | 286 base::UTF16ToUTF8(shortcut_info_.short_name)); |
| 253 web_app_manifest->set_start_url(shortcut_info_.url.spec()); | 287 web_app_manifest->set_start_url(shortcut_info_.url.spec()); |
| 254 web_app_manifest->set_orientation( | 288 web_app_manifest->set_orientation( |
| 255 content::WebScreenOrientationLockTypeToString( | 289 content::WebScreenOrientationLockTypeToString( |
| 256 shortcut_info_.orientation)); | 290 shortcut_info_.orientation)); |
| 257 web_app_manifest->set_display_mode( | 291 web_app_manifest->set_display_mode( |
| 258 content::WebDisplayModeToString(shortcut_info_.display)); | 292 content::WebDisplayModeToString(shortcut_info_.display)); |
| 259 web_app_manifest->set_background_color( | 293 web_app_manifest->set_background_color( |
| 260 ColorToString(shortcut_info_.background_color)); | 294 ColorToString(shortcut_info_.background_color)); |
| 261 web_app_manifest->set_theme_color(ColorToString(shortcut_info_.theme_color)); | 295 web_app_manifest->set_theme_color(ColorToString(shortcut_info_.theme_color)); |
| 262 | 296 |
| 263 std::string* scope = web_app_manifest->add_scopes(); | 297 std::string* scope = web_app_manifest->add_scopes(); |
| 264 scope->assign(GetScope(shortcut_info_).spec()); | 298 scope->assign(GetScope(shortcut_info_).spec()); |
| 265 webapk::Image* image = web_app_manifest->add_icons(); | 299 webapk::Image* image = web_app_manifest->add_icons(); |
| 266 image->set_src(shortcut_info_.icon_url.spec()); | 300 image->set_src(shortcut_info_.icon_url.spec()); |
| 267 // TODO(pkotwicz): Get Murmur2 hash of untransformed icon's bytes (with no | 301 // TODO(pkotwicz): Get Murmur2 hash of untransformed icon's bytes (with no |
| 268 // encoding/decoding). | 302 // encoding/decoding). |
| 269 image->set_hash(ComputeBitmapHash(shortcut_icon_)); | 303 image->set_hash(ComputeBitmapHash(shortcut_icon_)); |
| 270 std::vector<unsigned char> png_bytes; | 304 std::vector<unsigned char> png_bytes; |
| 271 gfx::PNGCodec::EncodeBGRASkBitmap(shortcut_icon_, false, &png_bytes); | 305 gfx::PNGCodec::EncodeBGRASkBitmap(shortcut_icon_, false, &png_bytes); |
| 272 image->set_image_data(&png_bytes.front(), png_bytes.size()); | 306 image->set_image_data(&png_bytes.front(), png_bytes.size()); |
| 273 | |
| 274 return request; | |
| 275 } | 307 } |
| 276 | 308 |
| 277 void WebApkInstaller::OnTimeout() { | 309 void WebApkInstaller::OnTimeout() { |
| 278 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 310 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 279 OnFailure(); | 311 OnFailure(); |
| 280 } | 312 } |
| 281 | 313 |
| 282 void WebApkInstaller::OnSuccess() { | 314 void WebApkInstaller::OnSuccess() { |
| 283 finish_callback_.Run(true); | 315 finish_callback_.Run(true); |
| 284 delete this; | 316 delete this; |
| 285 } | 317 } |
| 286 | 318 |
| 287 void WebApkInstaller::OnFailure() { | 319 void WebApkInstaller::OnFailure() { |
| 288 finish_callback_.Run(false); | 320 finish_callback_.Run(false); |
| 289 delete this; | 321 delete this; |
| 290 } | 322 } |
| OLD | NEW |