123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "android_webview/nonembedded/component_updater/aw_component_update_service.h"
- #include <stdint.h>
- #include <iterator>
- #include <memory>
- #include <utility>
- #include "android_webview/common/aw_paths.h"
- #include "android_webview/nonembedded/component_updater/aw_component_updater_configurator.h"
- #include "base/android/path_utils.h"
- #include "base/callback.h"
- #include "base/callback_helpers.h"
- #include "base/command_line.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/json/json_reader.h"
- #include "base/memory/raw_ptr.h"
- #include "base/test/android/url_utils.h"
- #include "base/test/task_environment.h"
- #include "base/values.h"
- #include "base/version.h"
- #include "components/component_updater/component_installer.h"
- #include "components/component_updater/component_updater_paths.h"
- #include "components/component_updater/component_updater_service.h"
- #include "components/prefs/testing_pref_service.h"
- #include "components/update_client/network.h"
- #include "components/update_client/update_client.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- namespace android_webview {
- namespace {
- // Size of android_webview/test/data/components/fake_component.crx.
- constexpr size_t kCrxContentLength = 3902;
- constexpr char kComponentId[] = "llkgjffcdpffmhiakmfcdcblohccpfmo";
- // This hash corresponds to kComponentId.
- constexpr uint8_t kSha256Hash[] = {
- 0xbb, 0xa6, 0x95, 0x52, 0x3f, 0x55, 0xc7, 0x80, 0xac, 0x52, 0x32,
- 0x1b, 0xe7, 0x22, 0xf5, 0xce, 0x6a, 0xfd, 0x9c, 0x9e, 0xa9, 0x2a,
- 0x0b, 0x50, 0x60, 0x2b, 0x7f, 0x6c, 0x64, 0x80, 0x09, 0x04};
- constexpr char kTestVersion[] = "1.0.0.6";
- base::FilePath GetTestFile(const std::string& file_name) {
- return base::android::GetIsolatedTestRoot()
- .AppendASCII("android_webview/test/data/components")
- .AppendASCII(file_name);
- }
- void CreateTestFiles(const base::FilePath& install_dir) {
- base::CreateDirectory(install_dir);
- ASSERT_TRUE(base::WriteFile(install_dir.AppendASCII("file1.txt"), "1"));
- ASSERT_TRUE(base::CopyFile(GetTestFile("fake_component_manifest.json"),
- install_dir.AppendASCII("manifest.json")));
- }
- void AssertOnDemandRequest(bool on_demand, std::string post_data) {
- const auto root = base::JSONReader::Read(post_data);
- ASSERT_TRUE(root);
- const auto* request = root->FindKey("request");
- ASSERT_TRUE(request);
- const auto& app = request->FindKey("app")->GetListDeprecated()[0];
- if (on_demand) {
- EXPECT_EQ("ondemand", app.FindKey("installsource")->GetString());
- } else {
- EXPECT_EQ(nullptr, app.FindKey("installsource"));
- }
- }
- class FailingNetworkFetcher : public update_client::NetworkFetcher {
- public:
- FailingNetworkFetcher() = default;
- ~FailingNetworkFetcher() override = default;
- FailingNetworkFetcher(const FailingNetworkFetcher&) = delete;
- FailingNetworkFetcher& operator=(const FailingNetworkFetcher&) = delete;
- // NetworkFetcher overrides.
- void PostRequest(
- const GURL& url,
- const std::string& post_data,
- const std::string& content_type,
- const base::flat_map<std::string, std::string>& post_additional_headers,
- ResponseStartedCallback response_started_callback,
- ProgressCallback progress_callback,
- PostRequestCompleteCallback post_request_complete_callback) override {
- AssertOnDemandRequest(false, post_data);
- std::move(post_request_complete_callback)
- .Run(/* response_body= */ std::make_unique<std::string>(""),
- /* network_error= */ -2,
- /* header_etag= */ "",
- /* header_x_cup_server_proof= */ "",
- /* x_header_retry_after_sec= */ 0ll);
- }
- void DownloadToFile(const GURL& url,
- const base::FilePath& file_path,
- ResponseStartedCallback response_started_callback,
- ProgressCallback progress_callback,
- DownloadToFileCompleteCallback
- download_to_file_complete_callback) override {
- std::move(download_to_file_complete_callback)
- .Run(
- /* network_error= */ -2,
- /* content_size= */ 0);
- }
- };
- // This inspects that param onDemandUpdate gets passed down the call stack.
- class OnDemandNetworkFetcher : public update_client::NetworkFetcher {
- public:
- OnDemandNetworkFetcher() = default;
- ~OnDemandNetworkFetcher() override = default;
- OnDemandNetworkFetcher(const OnDemandNetworkFetcher&) = delete;
- OnDemandNetworkFetcher& operator=(const OnDemandNetworkFetcher&) = delete;
- // NetworkFetcher overrides.
- void PostRequest(
- const GURL& url,
- const std::string& post_data,
- const std::string& content_type,
- const base::flat_map<std::string, std::string>& post_additional_headers,
- ResponseStartedCallback response_started_callback,
- ProgressCallback progress_callback,
- PostRequestCompleteCallback post_request_complete_callback) override {
- AssertOnDemandRequest(true, post_data);
- std::move(post_request_complete_callback)
- .Run(/* response_body= */ std::make_unique<std::string>(""),
- /* network_error= */ -2,
- /* header_etag= */ "",
- /* header_x_cup_server_proof= */ "",
- /* x_header_retry_after_sec= */ 0ll);
- }
- void DownloadToFile(const GURL& url,
- const base::FilePath& file_path,
- ResponseStartedCallback response_started_callback,
- ProgressCallback progress_callback,
- DownloadToFileCompleteCallback
- download_to_file_complete_callback) override {
- std::move(download_to_file_complete_callback)
- .Run(
- /* network_error= */ -2,
- /* content_size= */ 0);
- }
- };
- // A NetworkFetcher that fakes downloading a CRX file.
- // TODO(crbug.com/1190310) use EmbeddedTestServer instead of Mocking the
- // NetworkFetcher.
- class FakeCrxNetworkFetcher : public update_client::NetworkFetcher {
- public:
- FakeCrxNetworkFetcher() = default;
- ~FakeCrxNetworkFetcher() override = default;
- FakeCrxNetworkFetcher(const FakeCrxNetworkFetcher&) = delete;
- FakeCrxNetworkFetcher& operator=(const FakeCrxNetworkFetcher&) = delete;
- // NetworkFetcher overrides.
- void PostRequest(
- const GURL& url,
- const std::string& post_data,
- const std::string& content_type,
- const base::flat_map<std::string, std::string>& post_additional_headers,
- ResponseStartedCallback response_started_callback,
- ProgressCallback progress_callback,
- PostRequestCompleteCallback post_request_complete_callback) override {
- AssertOnDemandRequest(false, post_data);
- std::move(response_started_callback)
- .Run(/* responseCode= */ 200, /* content_size= */ 0);
- std::string response_body;
- int network_error = 0;
- if (post_data.find("updatecheck") != std::string::npos) {
- ASSERT_TRUE(base::ReadFileToString(
- GetTestFile("fake_component_update_response.json"), &response_body));
- } else if (post_data.find("eventtype") != std::string::npos) {
- ASSERT_TRUE(base::ReadFileToString(
- GetTestFile("fake_component_ping_response.json"), &response_body));
- } else { // error post request not a ping nor update.
- network_error = -2;
- }
- std::move(post_request_complete_callback)
- .Run(/* response_body= */ std::make_unique<std::string>(response_body),
- /* network_error= */ network_error,
- /* header_etag= */ "",
- /* header_x_cup_server_proof= */ "",
- /* x_header_retry_after_sec= */ 0ll);
- }
- void DownloadToFile(const GURL& url,
- const base::FilePath& file_path,
- ResponseStartedCallback response_started_callback,
- ProgressCallback progress_callback,
- DownloadToFileCompleteCallback
- download_to_file_complete_callback) override {
- ASSERT_TRUE(base::CopyFile(GetTestFile("fake_component.crx"), file_path));
- std::move(response_started_callback)
- .Run(/* responseCode= */ 200, /* content_size= */ kCrxContentLength);
- std::move(download_to_file_complete_callback)
- .Run(
- /* network_error= */ 0,
- /* content_size= */ kCrxContentLength);
- }
- };
- template <typename T>
- class MockNetworkFetcherFactory : public update_client::NetworkFetcherFactory {
- public:
- MockNetworkFetcherFactory() = default;
- MockNetworkFetcherFactory(const MockNetworkFetcherFactory&) = delete;
- MockNetworkFetcherFactory& operator=(const MockNetworkFetcherFactory&) =
- delete;
- std::unique_ptr<update_client::NetworkFetcher> Create() const override {
- return std::make_unique<T>();
- }
- protected:
- ~MockNetworkFetcherFactory() override = default;
- };
- class MockConfigurator : public AwComponentUpdaterConfigurator {
- public:
- explicit MockConfigurator(PrefService* pref_service,
- scoped_refptr<update_client::NetworkFetcherFactory>
- network_fetcher_factory)
- : AwComponentUpdaterConfigurator(base::CommandLine::ForCurrentProcess(),
- pref_service),
- network_fetcher_factory_(std::move(network_fetcher_factory)) {}
- scoped_refptr<update_client::NetworkFetcherFactory> GetNetworkFetcherFactory()
- override {
- return network_fetcher_factory_;
- }
- // Disable CUP signing so we can inject the fake CRX.
- bool EnabledCupSigning() const override { return false; }
- protected:
- ~MockConfigurator() override = default;
- private:
- scoped_refptr<update_client::NetworkFetcherFactory> network_fetcher_factory_;
- };
- class MockInstallerPolicy : public component_updater::ComponentInstallerPolicy {
- public:
- MockInstallerPolicy() = default;
- ~MockInstallerPolicy() override = default;
- MockInstallerPolicy(const MockInstallerPolicy&) = delete;
- MockInstallerPolicy& operator=(const MockInstallerPolicy&) = delete;
- // Overridden ComponentInstallerPolicy methods
- bool SupportsGroupPolicyEnabledComponentUpdates() const override {
- return false;
- }
- bool RequiresNetworkEncryption() const override { return false; }
- update_client::CrxInstaller::Result OnCustomInstall(
- const base::Value& manifest,
- const base::FilePath& install_dir) override {
- return update_client::CrxInstaller::Result(0);
- }
- void OnCustomUninstall() override { FAIL(); }
- void ComponentReady(const base::Version& version,
- const base::FilePath& install_dir,
- base::Value manifest) override {
- version_ = version;
- install_dir_ = install_dir;
- manifest_ = std::move(manifest);
- }
- bool VerifyInstallation(const base::Value& manifest,
- const base::FilePath& install_dir) const override {
- return true;
- }
- base::FilePath GetRelativeInstallDir() const override {
- return base::FilePath(FILE_PATH_LITERAL(kComponentId));
- }
- void GetHash(std::vector<uint8_t>* hash) const override {
- hash->assign(std::begin(kSha256Hash), std::end(kSha256Hash));
- }
- std::string GetName() const override { return kComponentId; }
- update_client::InstallerAttributes GetInstallerAttributes() const override {
- return update_client::InstallerAttributes();
- }
- bool IsComponentReadyInvoked() { return !!manifest_; }
- base::Value& GetManifest() { return *manifest_; }
- base::FilePath GetInstallDir() const { return install_dir_; }
- base::Version GetVersion() const { return version_; }
- private:
- absl::optional<base::Value> manifest_;
- base::FilePath install_dir_;
- base::Version version_;
- };
- } // namespace
- class TestAwComponentUpdateService : public AwComponentUpdateService {
- public:
- explicit TestAwComponentUpdateService(
- scoped_refptr<update_client::Configurator> configurator)
- : AwComponentUpdateService(configurator) {}
- ~TestAwComponentUpdateService() override = default;
- MockInstallerPolicy* GetMockPolicy() { return mock_policy_; }
- protected:
- void RegisterComponents(RegisterComponentsCallback register_callback,
- base::OnceClosure on_finished) override {
- auto policy = std::make_unique<MockInstallerPolicy>();
- mock_policy_ = policy.get();
- base::MakeRefCounted<component_updater::ComponentInstaller>(
- std::move(policy))
- ->Register(std::move(register_callback), std::move(on_finished));
- }
- private:
- raw_ptr<MockInstallerPolicy> mock_policy_;
- };
- class AwComponentUpdateServiceTest : public testing::Test {
- public:
- AwComponentUpdateServiceTest() = default;
- ~AwComponentUpdateServiceTest() override = default;
- AwComponentUpdateServiceTest(const AwComponentUpdateServiceTest&) = delete;
- AwComponentUpdateServiceTest& operator=(const AwComponentUpdateServiceTest&) =
- delete;
- static void SetUpTestSuite() {
- RegisterPathProvider();
- component_updater::RegisterPathProvider(
- /*components_system_root_key=*/android_webview::DIR_COMPONENTS_ROOT,
- /*components_system_root_key_alt=*/android_webview::DIR_COMPONENTS_ROOT,
- /*components_user_root_key=*/android_webview::DIR_COMPONENTS_ROOT);
- }
- // Override from testing::Test
- void SetUp() override {
- update_client::RegisterPrefs(test_pref_->registry());
- ASSERT_TRUE(base::android::GetDataDirectory(&component_install_dir_));
- component_install_dir_ = component_install_dir_.AppendASCII("components")
- .AppendASCII("cus")
- .AppendASCII(kComponentId);
- }
- void TearDown() override {
- if (base::PathExists(component_install_dir_))
- ASSERT_TRUE(base::DeletePathRecursively(component_install_dir_));
- }
- protected:
- base::FilePath component_install_dir_;
- std::unique_ptr<TestingPrefServiceSimple> test_pref_ =
- std::make_unique<TestingPrefServiceSimple>();
- private:
- base::test::TaskEnvironment task_environment_;
- };
- TEST_F(AwComponentUpdateServiceTest, TestComponentReadyWhenOffline) {
- CreateTestFiles(component_install_dir_.AppendASCII(kTestVersion));
- base::RunLoop run_loop;
- TestAwComponentUpdateService service(base::MakeRefCounted<MockConfigurator>(
- test_pref_.get(),
- base::MakeRefCounted<
- MockNetworkFetcherFactory<FailingNetworkFetcher>>()));
- base::OnceClosure closure = run_loop.QuitClosure();
- service.StartComponentUpdateService(
- base::BindOnce(
- [](base::OnceClosure closure, int) { std::move(closure).Run(); },
- std::move(closure)),
- false);
- run_loop.Run();
- ASSERT_TRUE(service.GetMockPolicy()->IsComponentReadyInvoked());
- EXPECT_EQ(service.GetMockPolicy()->GetVersion().GetString(), kTestVersion);
- EXPECT_EQ(service.GetMockPolicy()->GetInstallDir(),
- component_install_dir_.AppendASCII(kTestVersion));
- }
- TEST_F(AwComponentUpdateServiceTest, TestFreshDownloadingFakeApk) {
- base::RunLoop run_loop;
- TestAwComponentUpdateService service(base::MakeRefCounted<MockConfigurator>(
- test_pref_.get(),
- base::MakeRefCounted<
- MockNetworkFetcherFactory<FakeCrxNetworkFetcher>>()));
- base::OnceClosure closure = run_loop.QuitClosure();
- service.StartComponentUpdateService(
- base::BindOnce(
- [](base::OnceClosure closure, int) { std::move(closure).Run(); },
- std::move(closure)),
- false);
- run_loop.Run();
- ASSERT_TRUE(service.GetMockPolicy()->IsComponentReadyInvoked());
- EXPECT_EQ(service.GetMockPolicy()->GetVersion().GetString(), kTestVersion);
- EXPECT_EQ(service.GetMockPolicy()->GetInstallDir(),
- component_install_dir_.AppendASCII(kTestVersion));
- // Assert that the manifest is valid by asserting a field in it other than
- // version.
- std::string* minimum_chrome_version =
- service.GetMockPolicy()->GetManifest().FindStringKey(
- "minimum_chrome_version");
- ASSERT_TRUE(minimum_chrome_version);
- EXPECT_EQ(*minimum_chrome_version, "50");
- }
- TEST_F(AwComponentUpdateServiceTest, TestOnDemandUpdateRequest) {
- CreateTestFiles(component_install_dir_.AppendASCII(kTestVersion));
- base::RunLoop run_loop;
- TestAwComponentUpdateService service(base::MakeRefCounted<MockConfigurator>(
- test_pref_.get(),
- base::MakeRefCounted<
- MockNetworkFetcherFactory<OnDemandNetworkFetcher>>()));
- base::OnceClosure closure = run_loop.QuitClosure();
- service.StartComponentUpdateService(
- base::BindOnce(
- [](base::OnceClosure closure, int) { std::move(closure).Run(); },
- std::move(closure)),
- true);
- run_loop.Run();
- ASSERT_TRUE(service.GetMockPolicy()->IsComponentReadyInvoked());
- EXPECT_EQ(service.GetMockPolicy()->GetVersion().GetString(), kTestVersion);
- EXPECT_EQ(service.GetMockPolicy()->GetInstallDir(),
- component_install_dir_.AppendASCII(kTestVersion));
- }
- } // namespace android_webview
|