Chromium Code Reviews| Index: chrome/browser/android/webapk/webapk_installer.cc |
| diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc |
| index 417ffc62f21aa1485d682f37c1e023cc807f0770..5b6b4b2ba2fc81df9bf5436b09493cbd5fb2ace7 100644 |
| --- a/chrome/browser/android/webapk/webapk_installer.cc |
| +++ b/chrome/browser/android/webapk/webapk_installer.cc |
| @@ -13,7 +13,6 @@ |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/memory/ref_counted.h" |
| -#include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| @@ -21,15 +20,14 @@ |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "chrome/browser/android/shortcut_helper.h" |
| #include "chrome/browser/android/webapk/webapk.pb.h" |
| +#include "chrome/browser/android/webapk/webapk_icon_hasher.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "components/version_info/version_info.h" |
| #include "content/public/browser/browser_thread.h" |
| -#include "content/public/common/manifest_util.h" |
| #include "jni/WebApkInstaller_jni.h" |
| #include "net/http/http_status_code.h" |
| #include "net/url_request/url_fetcher.h" |
| -#include "third_party/smhasher/src/MurmurHash2.h" |
| #include "ui/gfx/codec/png_codec.h" |
| #include "url/gurl.h" |
| @@ -42,9 +40,6 @@ const char kDefaultWebApkServerUrl[] = |
| // The MIME type of the POST data sent to the server. |
| const char kProtoMimeType[] = "application/x-protobuf"; |
| -// The seed to use the murmur2 hash of the app icon. |
| -const uint32_t kMurmur2HashSeed = 0; |
| - |
| // The default number of milliseconds to wait for the WebAPK download URL from |
| // the WebAPK server. |
| const int kWebApkDownloadUrlTimeoutMs = 60000; |
| @@ -61,15 +56,6 @@ GURL GetScope(const ShortcutInfo& info) { |
| : ShortcutHelper::GetScopeFromURL(info.url); |
| } |
| -// Computes a murmur2 hash of |bitmap|'s PNG encoded bytes. |
| -std::string ComputeBitmapHash(const SkBitmap& bitmap) { |
| - std::vector<unsigned char> png_bytes; |
| - gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &png_bytes); |
| - uint64_t hash = |
| - MurmurHash64B(&png_bytes.front(), png_bytes.size(), kMurmur2HashSeed); |
| - return base::Uint64ToString(hash); |
| -} |
| - |
| // Converts a color from the format specified in content::Manifest to a CSS |
| // string. |
| std::string ColorToString(int64_t color) { |
| @@ -84,6 +70,46 @@ std::string ColorToString(int64_t color) { |
| return base::StringPrintf("rgba(%d,%d,%d,%.2f)", r, g, b, a); |
| } |
| +// Populates webapk::WebApk and returns it. |
| +// Must be called on a worker thread because it encodes an SkBitmap. |
| +std::unique_ptr<webapk::WebApk> BuildWebApkProtoInBackground( |
| + const ShortcutInfo& shortcut_info, |
| + const SkBitmap& shortcut_icon, |
| + const std::string& shortcut_icon_murmur2_hash) { |
| + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
| + |
| + std::unique_ptr<webapk::WebApk> webapk(new webapk::WebApk); |
| + webapk->set_manifest_url(shortcut_info.manifest_url.spec()); |
| + webapk->set_requester_application_package( |
| + base::android::BuildInfo::GetInstance()->package_name()); |
| + webapk->set_requester_application_version(version_info::GetVersionNumber()); |
| + |
| + webapk::WebAppManifest* web_app_manifest = webapk->mutable_manifest(); |
| + web_app_manifest->set_name(base::UTF16ToUTF8(shortcut_info.name)); |
| + web_app_manifest->set_short_name( |
| + base::UTF16ToUTF8(shortcut_info.short_name)); |
| + web_app_manifest->set_start_url(shortcut_info.url.spec()); |
| + web_app_manifest->set_orientation( |
| + content::WebScreenOrientationLockTypeToString( |
| + shortcut_info.orientation)); |
| + web_app_manifest->set_display_mode( |
| + content::WebDisplayModeToString(shortcut_info.display)); |
| + web_app_manifest->set_background_color( |
| + ColorToString(shortcut_info.background_color)); |
| + web_app_manifest->set_theme_color(ColorToString(shortcut_info.theme_color)); |
| + |
| + std::string* scope = web_app_manifest->add_scopes(); |
| + scope->assign(GetScope(shortcut_info).spec()); |
| + webapk::Image* image = web_app_manifest->add_icons(); |
| + image->set_src(shortcut_info.icon_url.spec()); |
| + image->set_hash(shortcut_icon_murmur2_hash); |
| + std::vector<unsigned char> png_bytes; |
| + gfx::PNGCodec::EncodeBGRASkBitmap(shortcut_icon, false, &png_bytes); |
| + image->set_image_data(&png_bytes.front(), png_bytes.size()); |
| + |
| + return webapk; |
| +} |
| + |
| // Returns task runner for running background tasks. |
| scoped_refptr<base::TaskRunner> GetBackgroundTaskRunner() { |
| return content::BrowserThread::GetBlockingPool() |
| @@ -122,18 +148,20 @@ void WebApkInstaller::InstallAsyncWithURLRequestContextGetter( |
| request_context_getter_ = request_context_getter; |
| finish_callback_ = finish_callback; |
| - // base::Unretained() is safe because WebApkInstaller owns itself and does not |
| - // start the timeout timer till after SendCreateWebApkRequest() is called. |
| - scoped_refptr<base::TaskRunner> background_task_runner = |
| - content::BrowserThread::GetBlockingPool() |
| - ->GetTaskRunnerWithShutdownBehavior( |
| - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| - base::PostTaskAndReplyWithResult( |
| - background_task_runner.get(), FROM_HERE, |
| - base::Bind(&WebApkInstaller::BuildWebApkProtoInBackground, |
| - base::Unretained(this)), |
| - base::Bind(&WebApkInstaller::SendCreateWebApkRequest, |
| - base::Unretained(this))); |
| + if (shortcut_info_.icon_url.is_valid()) { |
| + // We need to take the hash of the bitmap at the icon URL prior to any |
| + // transformations being applied to the bitmap (such as encoding/decoding |
| + // the bitmap). The WebAPK server crawls the internet and generates WebAPKs |
|
Yaron
2016/08/12 21:24:05
it doesn't actually crawl the internet per-say and
|
| + // for any Web Manifests that it finds. The icon hash is used to determine |
| + // whether the icon that the user sees matches the icon of a WebAPK that the |
| + // WebAPK server generated while crawling the internet. |
| + // |
| + // We redownload the icon in order to take the Murmur2 hash. The redownload |
| + // should be fast because the icon should be in the HTTP cache. |
|
Yaron
2016/08/12 21:24:05
have you tested that locally? is there a way to se
pkotwicz
2016/08/15 17:19:26
Yes, I have tested locally and the icon is loaded
|
| + DownloadAppIconAndComputeMurmur2Hash(); |
| + return; |
| + } |
| + SendCreateWebApkRequest(); |
| } |
| void WebApkInstaller::SetTimeoutMs(int timeout_ms) { |
| @@ -176,7 +204,44 @@ void WebApkInstaller::OnURLFetchComplete(const net::URLFetcher* source) { |
| OnGotWebApkDownloadUrl(signed_download_url, response->package_name()); |
| } |
| -void WebApkInstaller::SendCreateWebApkRequest( |
| +void WebApkInstaller::DownloadAppIconAndComputeMurmur2Hash() { |
| + timer_.Start( |
| + FROM_HERE, base::TimeDelta::FromMilliseconds(download_timeout_ms_), |
| + base::Bind(&WebApkInstaller::OnTimeout, weak_ptr_factory_.GetWeakPtr())); |
| + |
| + icon_hasher_.reset(new WebApkIconHasher()); |
| + icon_hasher_->DownloadAndGetMurmur2Hash( |
| + request_context_getter_, shortcut_info_.icon_url, |
| + base::Bind(&WebApkInstaller::OnGotIconMurmur2Hash, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void WebApkInstaller::OnGotIconMurmur2Hash( |
| + const std::string& icon_murmur2_hash) { |
| + timer_.Stop(); |
| + icon_hasher_.reset(); |
| + |
| + shortcut_icon_murmur2_hash_ = icon_murmur2_hash; |
| + |
| + // An empty hash indicates that |icon_hasher_| encountered an error. |
| + if (icon_murmur2_hash.empty()) { |
| + OnFailure(); |
| + return; |
| + } |
| + |
| + SendCreateWebApkRequest(); |
| +} |
| + |
| +void WebApkInstaller::SendCreateWebApkRequest() { |
| + base::PostTaskAndReplyWithResult( |
| + GetBackgroundTaskRunner().get(), FROM_HERE, |
| + base::Bind(&BuildWebApkProtoInBackground, shortcut_info_, shortcut_icon_, |
| + shortcut_icon_murmur2_hash_), |
| + base::Bind(&WebApkInstaller::SendCreateWebApkRequestWithProto, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void WebApkInstaller::SendCreateWebApkRequestWithProto( |
| std::unique_ptr<webapk::WebApk> webapk_proto) { |
| timer_.Start( |
| FROM_HERE, |
| @@ -254,54 +319,18 @@ void WebApkInstaller::OnWebApkMadeWorldReadable( |
| OnFailure(); |
| } |
| -std::unique_ptr<webapk::WebApk> |
| -WebApkInstaller::BuildWebApkProtoInBackground() { |
| - DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
| - |
| - std::unique_ptr<webapk::WebApk> webapk(new webapk::WebApk); |
| - webapk->set_manifest_url(shortcut_info_.manifest_url.spec()); |
| - webapk->set_requester_application_package( |
| - base::android::BuildInfo::GetInstance()->package_name()); |
| - webapk->set_requester_application_version(version_info::GetVersionNumber()); |
| - |
| - webapk::WebAppManifest* web_app_manifest = webapk->mutable_manifest(); |
| - web_app_manifest->set_name(base::UTF16ToUTF8(shortcut_info_.name)); |
| - web_app_manifest->set_short_name( |
| - base::UTF16ToUTF8(shortcut_info_.short_name)); |
| - web_app_manifest->set_start_url(shortcut_info_.url.spec()); |
| - web_app_manifest->set_orientation( |
| - content::WebScreenOrientationLockTypeToString( |
| - shortcut_info_.orientation)); |
| - web_app_manifest->set_display_mode( |
| - content::WebDisplayModeToString(shortcut_info_.display)); |
| - web_app_manifest->set_background_color( |
| - ColorToString(shortcut_info_.background_color)); |
| - web_app_manifest->set_theme_color(ColorToString(shortcut_info_.theme_color)); |
| - |
| - std::string* scope = web_app_manifest->add_scopes(); |
| - scope->assign(GetScope(shortcut_info_).spec()); |
| - webapk::Image* image = web_app_manifest->add_icons(); |
| - image->set_src(shortcut_info_.icon_url.spec()); |
| - // TODO(pkotwicz): Get Murmur2 hash of untransformed icon's bytes (with no |
| - // encoding/decoding). |
| - image->set_hash(ComputeBitmapHash(shortcut_icon_)); |
| - std::vector<unsigned char> png_bytes; |
| - gfx::PNGCodec::EncodeBGRASkBitmap(shortcut_icon_, false, &png_bytes); |
| - image->set_image_data(&png_bytes.front(), png_bytes.size()); |
| - |
| - return webapk; |
| -} |
| - |
| void WebApkInstaller::OnTimeout() { |
| OnFailure(); |
| } |
| void WebApkInstaller::OnSuccess() { |
| - finish_callback_.Run(true); |
| + FinishCallback callback = finish_callback_; |
| delete this; |
| + callback.Run(true); |
| } |
| void WebApkInstaller::OnFailure() { |
| - finish_callback_.Run(false); |
| + FinishCallback callback = finish_callback_; |
| delete this; |
| + callback.Run(false); |
| } |