| 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 783397b8b1c805d8987a366780fcc2ae93c74689..b483f915bf0b2a634aeccf407fa07bc1e115ffdc 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,6 +20,7 @@
|
| #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"
|
| @@ -29,7 +29,6 @@
|
| #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 +41,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 +57,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 +71,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,14 +149,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.
|
| - base::PostTaskAndReplyWithResult(
|
| - GetBackgroundTaskRunner().get(), FROM_HERE,
|
| - base::Bind(&WebApkInstaller::BuildWebApkProtoInBackground,
|
| - base::Unretained(this)),
|
| - base::Bind(&WebApkInstaller::SendCreateWebApkRequest,
|
| - base::Unretained(this)));
|
| + if (!shortcut_info_.icon_url.is_valid()) {
|
| + OnFailure();
|
| + return;
|
| + }
|
| +
|
| + // 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 icon hash is used to determine whether the icon that
|
| + // the user sees matches the icon of a WebAPK that the WebAPK server
|
| + // generated for another user. (The icon can be dynamically generated.)
|
| + //
|
| + // 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.
|
| + DownloadAppIconAndComputeMurmur2Hash();
|
| }
|
|
|
| void WebApkInstaller::SetTimeoutMs(int timeout_ms) {
|
| @@ -172,6 +205,39 @@ void WebApkInstaller::OnURLFetchComplete(const net::URLFetcher* source) {
|
| OnGotWebApkDownloadUrl(signed_download_url, response->package_name());
|
| }
|
|
|
| +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_->DownloadAndComputeMurmur2Hash(
|
| + 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;
|
| + }
|
| +
|
| + base::PostTaskAndReplyWithResult(
|
| + GetBackgroundTaskRunner().get(), FROM_HERE,
|
| + base::Bind(&BuildWebApkProtoInBackground, shortcut_info_, shortcut_icon_,
|
| + shortcut_icon_murmur2_hash_),
|
| + base::Bind(&WebApkInstaller::SendCreateWebApkRequest,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| void WebApkInstaller::SendCreateWebApkRequest(
|
| std::unique_ptr<webapk::WebApk> webapk_proto) {
|
| timer_.Start(
|
| @@ -250,54 +316,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);
|
| }
|
|
|