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