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 |