aw_apps_package_names_allowlist_component_loader_policy_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.h"
  5. #include <fcntl.h>
  6. #include <stdio.h>
  7. #include <unistd.h>
  8. #include <utility>
  9. #include "android_webview/browser/metrics/aw_metrics_service_client.h"
  10. #include "android_webview/common/metrics/app_package_name_logging_rule.h"
  11. #include "base/containers/flat_map.h"
  12. #include "base/files/file_path.h"
  13. #include "base/files/file_util.h"
  14. #include "base/files/scoped_file.h"
  15. #include "base/metrics/user_metrics.h"
  16. #include "base/run_loop.h"
  17. #include "base/sequence_checker.h"
  18. #include "base/test/bind.h"
  19. #include "base/test/metrics/histogram_tester.h"
  20. #include "base/test/task_environment.h"
  21. #include "base/time/time.h"
  22. #include "base/values.h"
  23. #include "base/version.h"
  24. #include "components/component_updater/android/component_loader_policy.h"
  25. #include "components/optimization_guide/core/bloom_filter.h"
  26. #include "components/prefs/testing_pref_service.h"
  27. #include "testing/gtest/include/gtest/gtest.h"
  28. namespace android_webview {
  29. using AllowlistPraseStatus =
  30. AwAppsPackageNamesAllowlistComponentLoaderPolicy::AllowlistPraseStatus;
  31. namespace {
  32. constexpr int kNumHash = 11;
  33. constexpr int kNumBitsPerEntry = 16;
  34. constexpr char kTestAllowlistVersion[] = "123.456.789.10";
  35. const std::string kTestAllowlist[] = {"com.example.test", "my.fake.app",
  36. "yet.another.app"};
  37. constexpr char kAllowlistPraseStatusHistogramName[] =
  38. "Android.WebView.Metrics.PackagesAllowList.ParseStatus";
  39. double MillisFromUnixEpoch(const base::Time& time) {
  40. return (time - base::Time::UnixEpoch()).InMillisecondsF();
  41. }
  42. std::unique_ptr<base::Value> BuildTestManifest() {
  43. auto manifest = std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
  44. manifest->SetKey(kBloomFilterNumHashKey, base::Value(kNumHash));
  45. manifest->SetKey(kBloomFilterNumBitsKey, base::Value(3 * kNumBitsPerEntry));
  46. manifest->SetKey(
  47. kExpiryDateKey,
  48. base::Value(MillisFromUnixEpoch(base::Time::Now() + base::Days(1))));
  49. return manifest;
  50. }
  51. } // namespace
  52. class AwAppsPackageNamesAllowlistComponentLoaderPolicyTest
  53. : public ::testing::Test {
  54. public:
  55. void SetUp() override {
  56. ASSERT_TRUE(base::CreateTemporaryFile(&allowlist_path_));
  57. }
  58. void TearDown() override {
  59. base::DeleteFile(allowlist_path_);
  60. }
  61. void WriteAllowListToFile(const std::vector<uint8_t>& data) {
  62. ASSERT_TRUE(base::WriteFile(allowlist_path_, data));
  63. }
  64. void WritePackageNamesAllowListToFile() {
  65. auto filter = std::make_unique<optimization_guide::BloomFilter>(
  66. kNumHash, kNumBitsPerEntry * std::size(kTestAllowlist));
  67. for (const auto& package : kTestAllowlist) {
  68. filter->Add(package);
  69. }
  70. WriteAllowListToFile(filter->bytes());
  71. }
  72. base::ScopedFD OpenAndGetAllowlistFd() {
  73. int allowlist_fd = open(allowlist_path_.value().c_str(), O_RDONLY);
  74. CHECK(allowlist_fd) << "Failed to open FD for " << allowlist_path_;
  75. return base::ScopedFD(allowlist_fd);
  76. }
  77. void LookupConfirmationCallback(
  78. absl::optional<AppPackageNameLoggingRule> record) {
  79. EXPECT_TRUE(checker_.CalledOnValidSequence());
  80. allowlist_lookup_result_ = record;
  81. lookup_run_loop_.Quit();
  82. }
  83. protected:
  84. base::test::TaskEnvironment env_;
  85. // Has to be init after TaskEnvironment.
  86. base::SequenceCheckerImpl checker_;
  87. base::RunLoop lookup_run_loop_;
  88. base::HistogramTester histogram_tester_;
  89. absl::optional<AppPackageNameLoggingRule> allowlist_lookup_result_;
  90. private:
  91. base::FilePath allowlist_path_;
  92. };
  93. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  94. TestExistingPackageName) {
  95. WritePackageNamesAllowListToFile();
  96. base::flat_map<std::string, base::ScopedFD> fd_map;
  97. fd_map[kAllowlistBloomFilterFileName] = OpenAndGetAllowlistFd();
  98. std::unique_ptr<base::Value> manifest = BuildTestManifest();
  99. base::Time one_day_from_now = base::Time::Now() + base::Days(1);
  100. manifest->SetDoubleKey(kExpiryDateKey, MillisFromUnixEpoch(one_day_from_now));
  101. base::Version new_version(kTestAllowlistVersion);
  102. auto policy =
  103. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  104. kTestAllowlist[1],
  105. AppPackageNameLoggingRule(base::Version("123.456.789.0"),
  106. base::Time::Min()),
  107. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  108. LookupConfirmationCallback,
  109. base::Unretained(this)));
  110. policy->ComponentLoaded(new_version, fd_map,
  111. base::DictionaryValue::From(std::move(manifest)));
  112. lookup_run_loop_.Run();
  113. ASSERT_TRUE(allowlist_lookup_result_.has_value());
  114. EXPECT_TRUE(allowlist_lookup_result_.value().IsAppPackageNameAllowed());
  115. EXPECT_EQ(allowlist_lookup_result_.value().GetVersion(), new_version);
  116. EXPECT_EQ(allowlist_lookup_result_.value().GetExpiryDate(), one_day_from_now);
  117. histogram_tester_.ExpectBucketCount(kAllowlistPraseStatusHistogramName,
  118. AllowlistPraseStatus::kSuccess, 1);
  119. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  120. }
  121. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  122. TestSameVersionAsCache) {
  123. base::flat_map<std::string, base::ScopedFD> fd_map;
  124. std::unique_ptr<base::Value> manifest = BuildTestManifest();
  125. base::Time one_day_from_now = base::Time::Now() + base::Days(1);
  126. base::Version version(kTestAllowlistVersion);
  127. AppPackageNameLoggingRule expected_record(version, one_day_from_now);
  128. auto policy =
  129. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  130. "test.some.app", expected_record,
  131. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  132. LookupConfirmationCallback,
  133. base::Unretained(this)));
  134. policy->ComponentLoaded(version, fd_map,
  135. base::DictionaryValue::From(std::move(manifest)));
  136. lookup_run_loop_.Run();
  137. ASSERT_TRUE(allowlist_lookup_result_.has_value());
  138. EXPECT_TRUE(allowlist_lookup_result_.value().IsAppPackageNameAllowed());
  139. EXPECT_TRUE(expected_record.IsSameAs(allowlist_lookup_result_.value()));
  140. histogram_tester_.ExpectBucketCount(kAllowlistPraseStatusHistogramName,
  141. AllowlistPraseStatus::kUsingCache, 1);
  142. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  143. }
  144. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  145. TestNonExistingPackageName) {
  146. WritePackageNamesAllowListToFile();
  147. base::flat_map<std::string, base::ScopedFD> fd_map;
  148. fd_map[kAllowlistBloomFilterFileName] = OpenAndGetAllowlistFd();
  149. base::Version new_version(kTestAllowlistVersion);
  150. auto policy =
  151. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  152. "non.existent.app", absl::optional<AppPackageNameLoggingRule>(),
  153. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  154. LookupConfirmationCallback,
  155. base::Unretained(this)));
  156. policy->ComponentLoaded(new_version, fd_map,
  157. base::DictionaryValue::From(BuildTestManifest()));
  158. lookup_run_loop_.Run();
  159. ASSERT_TRUE(allowlist_lookup_result_.has_value());
  160. EXPECT_EQ(allowlist_lookup_result_.value().GetVersion(), new_version);
  161. EXPECT_FALSE(allowlist_lookup_result_.value().IsAppPackageNameAllowed());
  162. histogram_tester_.ExpectBucketCount(kAllowlistPraseStatusHistogramName,
  163. AllowlistPraseStatus::kSuccess, 1);
  164. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  165. }
  166. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  167. TestAllowlistFileNotInMap) {
  168. base::flat_map<std::string, base::ScopedFD> fd_map;
  169. fd_map["another_file"] = OpenAndGetAllowlistFd();
  170. auto policy =
  171. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  172. kTestAllowlist[1], absl::optional<AppPackageNameLoggingRule>(),
  173. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  174. LookupConfirmationCallback,
  175. base::Unretained(this)));
  176. policy->ComponentLoaded(base::Version(kTestAllowlistVersion), fd_map,
  177. base::DictionaryValue::From(BuildTestManifest()));
  178. lookup_run_loop_.Run();
  179. EXPECT_FALSE(allowlist_lookup_result_.has_value());
  180. histogram_tester_.ExpectBucketCount(
  181. kAllowlistPraseStatusHistogramName,
  182. AllowlistPraseStatus::kMissingAllowlistFile, 1);
  183. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  184. }
  185. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  186. TestMissingBloomFilterParams) {
  187. WritePackageNamesAllowListToFile();
  188. base::flat_map<std::string, base::ScopedFD> fd_map;
  189. fd_map[kAllowlistBloomFilterFileName] = OpenAndGetAllowlistFd();
  190. auto policy =
  191. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  192. kTestAllowlist[1], absl::optional<AppPackageNameLoggingRule>(),
  193. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  194. LookupConfirmationCallback,
  195. base::Unretained(this)));
  196. policy->ComponentLoaded(base::Version(kTestAllowlistVersion), fd_map,
  197. std::make_unique<base::DictionaryValue>());
  198. lookup_run_loop_.Run();
  199. EXPECT_FALSE(allowlist_lookup_result_.has_value());
  200. histogram_tester_.ExpectBucketCount(kAllowlistPraseStatusHistogramName,
  201. AllowlistPraseStatus::kMissingFields, 1);
  202. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  203. }
  204. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  205. TestTooShortBloomFilter) {
  206. WriteAllowListToFile(std::vector<uint8_t>(2, 0xff));
  207. base::flat_map<std::string, base::ScopedFD> fd_map;
  208. fd_map[kAllowlistBloomFilterFileName] = OpenAndGetAllowlistFd();
  209. auto policy =
  210. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  211. kTestAllowlist[1], absl::optional<AppPackageNameLoggingRule>(),
  212. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  213. LookupConfirmationCallback,
  214. base::Unretained(this)));
  215. policy->ComponentLoaded(base::Version(kTestAllowlistVersion), fd_map,
  216. base::DictionaryValue::From(BuildTestManifest()));
  217. lookup_run_loop_.Run();
  218. EXPECT_FALSE(allowlist_lookup_result_.has_value());
  219. histogram_tester_.ExpectBucketCount(
  220. kAllowlistPraseStatusHistogramName,
  221. AllowlistPraseStatus::kMalformedBloomFilter, 1);
  222. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  223. }
  224. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  225. TestTooLongBloomFilter) {
  226. WriteAllowListToFile(std::vector<uint8_t>(2000, 0xff));
  227. base::flat_map<std::string, base::ScopedFD> fd_map;
  228. fd_map[kAllowlistBloomFilterFileName] = OpenAndGetAllowlistFd();
  229. auto policy =
  230. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  231. kTestAllowlist[1], absl::optional<AppPackageNameLoggingRule>(),
  232. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  233. LookupConfirmationCallback,
  234. base::Unretained(this)));
  235. policy->ComponentLoaded(base::Version(kTestAllowlistVersion), fd_map,
  236. base::DictionaryValue::From(BuildTestManifest()));
  237. lookup_run_loop_.Run();
  238. EXPECT_FALSE(allowlist_lookup_result_.has_value());
  239. histogram_tester_.ExpectBucketCount(
  240. kAllowlistPraseStatusHistogramName,
  241. AllowlistPraseStatus::kMalformedBloomFilter, 1);
  242. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  243. }
  244. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  245. TestExpiredAllowlist) {
  246. WritePackageNamesAllowListToFile();
  247. base::flat_map<std::string, base::ScopedFD> fd_map;
  248. fd_map[kAllowlistBloomFilterFileName] = OpenAndGetAllowlistFd();
  249. std::unique_ptr<base::Value> manifest = BuildTestManifest();
  250. manifest->SetKey(
  251. kExpiryDateKey,
  252. base::Value(MillisFromUnixEpoch(base::Time::Now() - base::Days(1))));
  253. auto policy =
  254. std::make_unique<AwAppsPackageNamesAllowlistComponentLoaderPolicy>(
  255. kTestAllowlist[1], absl::optional<AppPackageNameLoggingRule>(),
  256. base::BindOnce(&AwAppsPackageNamesAllowlistComponentLoaderPolicyTest::
  257. LookupConfirmationCallback,
  258. base::Unretained(this)));
  259. policy->ComponentLoaded(base::Version(kTestAllowlistVersion), fd_map,
  260. base::DictionaryValue::From(std::move(manifest)));
  261. lookup_run_loop_.Run();
  262. EXPECT_FALSE(allowlist_lookup_result_.has_value());
  263. histogram_tester_.ExpectBucketCount(kAllowlistPraseStatusHistogramName,
  264. AllowlistPraseStatus::kExpiredAllowlist,
  265. 1);
  266. histogram_tester_.ExpectTotalCount(kAllowlistPraseStatusHistogramName, 1);
  267. }
  268. // Helper functions for throttling tests, defining them near tests body for
  269. // better readability.
  270. namespace {
  271. class AwMetricsServiceClientTestDelegate
  272. : public AwMetricsServiceClient::Delegate {
  273. void RegisterAdditionalMetricsProviders(
  274. metrics::MetricsService* service) override {}
  275. void AddWebViewAppStateObserver(WebViewAppStateObserver* observer) override {}
  276. bool HasAwContentsEverCreated() const override { return false; }
  277. };
  278. void TestThrottling(base::Time time,
  279. AwMetricsServiceClient* client,
  280. bool expect_throttling) {
  281. if (!time.is_null()) {
  282. client->SetAppPackageNameLoggingRuleLastUpdateTime(time);
  283. }
  284. component_updater::ComponentLoaderPolicyVector policies;
  285. LoadPackageNamesAllowlistComponent(policies, client);
  286. EXPECT_EQ(policies.size(), expect_throttling ? 0 : 1u);
  287. }
  288. void TestThrottlingAllowlist(absl::optional<AppPackageNameLoggingRule> rule,
  289. bool expect_throttling) {
  290. TestingPrefServiceSimple prefs;
  291. AwMetricsServiceClient::RegisterMetricsPrefs(prefs.registry());
  292. AwMetricsServiceClient client(
  293. std::make_unique<AwMetricsServiceClientTestDelegate>());
  294. client.Initialize(&prefs);
  295. client.SetAppPackageNameLoggingRule(rule);
  296. // No previous last_update record: should never throttle.
  297. TestThrottling(base::Time(), &client, /*expect_throttling=*/false);
  298. // last_update record > max_throttle_time : should never throttle.
  299. TestThrottling(base::Time::Now() - kWebViewAppsMaxAllowlistThrottleTimeDelta -
  300. base::Days(1),
  301. &client,
  302. /*expect_throttling=*/false);
  303. // min_throttle_time < last_update record < max_throttle_time : maybe
  304. // throttle.
  305. TestThrottling(base::Time::Now() - kWebViewAppsMaxAllowlistThrottleTimeDelta +
  306. kWebViewAppsMinAllowlistThrottleTimeDelta,
  307. &client,
  308. /*expect_throttling=*/expect_throttling);
  309. // last_update record < min_throttle_time : should always throttle.
  310. TestThrottling(base::Time::Now() - kWebViewAppsMinAllowlistThrottleTimeDelta +
  311. base::Minutes(30),
  312. &client,
  313. /*expect_throttling=*/true);
  314. }
  315. } // namespace
  316. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  317. TestThrottlingAllowlist_AbsentCache) {
  318. base::SetRecordActionTaskRunner(env_.GetMainThreadTaskRunner());
  319. TestThrottlingAllowlist(absl::optional<AppPackageNameLoggingRule>(),
  320. /*expect_throttling=*/false);
  321. }
  322. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  323. TestThrottlingAllowlist_ValidCacheAllowedApp) {
  324. base::SetRecordActionTaskRunner(env_.GetMainThreadTaskRunner());
  325. TestThrottlingAllowlist(
  326. AppPackageNameLoggingRule(base::Version(kTestAllowlistVersion),
  327. base::Time::Now() + base::Days(1)),
  328. /*expect_throttling=*/true);
  329. }
  330. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  331. TestThrottlingAllowlist_ValidCacheNotAllowedApp) {
  332. base::SetRecordActionTaskRunner(env_.GetMainThreadTaskRunner());
  333. TestThrottlingAllowlist(
  334. AppPackageNameLoggingRule(base::Version(kTestAllowlistVersion),
  335. base::Time::Min()),
  336. /*expect_throttling=*/true);
  337. }
  338. TEST_F(AwAppsPackageNamesAllowlistComponentLoaderPolicyTest,
  339. TestThrottlingAllowlist_ExpiredAllowedCache) {
  340. base::SetRecordActionTaskRunner(env_.GetMainThreadTaskRunner());
  341. TestThrottlingAllowlist(
  342. AppPackageNameLoggingRule(base::Version(kTestAllowlistVersion),
  343. base::Time::Now() - base::Days(1)),
  344. /*expect_throttling=*/false);
  345. }
  346. } // namespace android_webview