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 |