| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 
 | // Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync_preferences/dual_layer_user_pref_store.h"
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include "base/auto_reset.h"
#include "base/barrier_closure.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/observer_list.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "components/sync/base/features.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/service/sync_user_settings.h"
#include "components/sync_preferences/pref_model_associator_client.h"
#include "components/sync_preferences/preferences_merge_helper.h"
#include "components/sync_preferences/syncable_prefs_database.h"
namespace sync_preferences {
namespace {
// This is the set of user selectable types that are relevant to
// `DualLayerUserPrefStore`. This is used to detect no-op changes to the user
// selected types efficiently.
constexpr syncer::UserSelectableTypeSet kInterestingUserSelectableTypes = {
    syncer::UserSelectableType::kPreferences,
    syncer::UserSelectableType::kHistory};
// The name of the pref storing the set of user selected types on the local pref
// store.
constexpr std::string_view kUserSelectedTypesPrefName =
    "dual_layer_user_pref_store.user_selected_sync_types";
}  // namespace
DualLayerUserPrefStore::UnderlyingPrefStoreObserver::
    UnderlyingPrefStoreObserver(DualLayerUserPrefStore* outer,
                                bool is_account_store)
    : outer_(outer), is_account_store_(is_account_store) {
  DCHECK(outer_);
}
void DualLayerUserPrefStore::UnderlyingPrefStoreObserver::OnPrefValueChanged(
    std::string_view key) {
  // Ignore this notification if it originated from the outer store - in that
  // case, `DualLayerUserPrefStore` itself will send notifications as
  // appropriate. This avoids dual notifications even though there are dual
  // writes.
  if (outer_->is_setting_prefs_) {
    return;
  }
  // Otherwise: This must've been a write directly to the underlying store, so
  // notify any observers.
  // Note: Observers should only be notified if the effective value of a pref
  // changes.
  // Note: The effective value will not change if this is a write to the local
  // store, but the account store has a value that overrides it.
  if (!is_account_store_ &&
      outer_->GetAccountPrefStore()->GetValue(key, nullptr) &&
      !outer_->IsPrefKeyMergeable(key)) {
    return;
  }
  for (PrefStore::Observer& observer : outer_->observers_) {
    observer.OnPrefValueChanged(key);
  }
}
void DualLayerUserPrefStore::UnderlyingPrefStoreObserver::
    OnInitializationCompleted(bool succeeded) {
  initialization_succeeded_ = succeeded;
  // Notify observers only after all underlying PrefStores are initialized.
  if (!outer_->IsInitializationComplete()) {
    return;
  }
  // Forward error if any of the underlying store reported error upon
  // ReadPrefsAsync().
  if (outer_->read_error_delegate_.has_value() &&
      outer_->read_error_delegate_.value()) {
    if (auto read_error = outer_->GetReadError();
        read_error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
      outer_->read_error_delegate_.value()->OnError(read_error);
    }
  }
  for (auto& observer : outer_->observers_) {
    observer.OnInitializationCompleted(outer_->IsInitializationSuccessful());
  }
}
bool DualLayerUserPrefStore::UnderlyingPrefStoreObserver::
    initialization_succeeded() const {
  CHECK(outer_->IsInitializationComplete());
  return initialization_succeeded_;
}
DualLayerUserPrefStore::DualLayerUserPrefStore(
    scoped_refptr<PersistentPrefStore> local_pref_store,
    scoped_refptr<PersistentPrefStore> account_pref_store,
    scoped_refptr<PrefModelAssociatorClient> pref_model_associator_client)
    : local_pref_store_(std::move(local_pref_store)),
      account_pref_store_(std::move(account_pref_store)),
      local_pref_store_observer_(this, /*is_account_store=*/false),
      account_pref_store_observer_(this, /*is_account_store=*/true),
      pref_model_associator_client_(pref_model_associator_client) {
  local_pref_store_->AddObserver(&local_pref_store_observer_);
  account_pref_store_->AddObserver(&account_pref_store_observer_);
}
DualLayerUserPrefStore::~DualLayerUserPrefStore() {
  account_pref_store_->RemoveObserver(&account_pref_store_observer_);
  local_pref_store_->RemoveObserver(&local_pref_store_observer_);
}
scoped_refptr<PersistentPrefStore> DualLayerUserPrefStore::GetLocalPrefStore() {
  return local_pref_store_;
}
scoped_refptr<WriteablePrefStore>
DualLayerUserPrefStore::GetAccountPrefStore() {
  return account_pref_store_;
}
void DualLayerUserPrefStore::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}
void DualLayerUserPrefStore::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}
bool DualLayerUserPrefStore::HasObservers() const {
  return !observers_.empty();
}
bool DualLayerUserPrefStore::IsInitializationComplete() const {
  return local_pref_store_->IsInitializationComplete() &&
         account_pref_store_->IsInitializationComplete();
}
bool DualLayerUserPrefStore::GetValue(std::string_view key,
                                      const base::Value** result) const {
  if (!ShouldGetValueFromAccountStore(key)) {
    return local_pref_store_->GetValue(key, result);
  }
  const base::Value* account_value = nullptr;
  const base::Value* local_value = nullptr;
  account_pref_store_->GetValue(key, &account_value);
  local_pref_store_->GetValue(key, &local_value);
  if (!account_value && !local_value) {
    // Pref doesn't exist.
    return false;
  }
  if (result) {
    // Merge pref if `key` exists in both the stores.
    if (account_value && local_value) {
      *result = MaybeMerge(key, *local_value, *account_value);
      CHECK(*result);
    } else if (account_value) {
      *result = account_value;
    } else {
      *result = local_value;
    }
  }
  return true;
}
base::Value::Dict DualLayerUserPrefStore::GetValues() const {
  base::Value::Dict values = local_pref_store_->GetValues();
  for (const std::string& pref_name : GetPrefNamesInAccountStore()) {
    // Filter out prefs which should not be queried from the account store, for
    // example, prefs requiring history opt-in if history sync is off.
    if (ShouldGetValueFromAccountStore(pref_name)) {
      const base::Value* value = nullptr;
      // GetValue() will merge the value if needed.
      GetValue(pref_name, &value);
      CHECK(value);
      values.SetByDottedPath(pref_name, value->Clone());
    }
  }
  return values;
}
void DualLayerUserPrefStore::SetValue(std::string_view key,
                                      base::Value value,
                                      uint32_t flags) {
  const base::Value* initial_value = nullptr;
  // Only notify if something actually changed.
  // Note: `value` is still added to the stores in case `key` was missing from
  // any or had a different value.
  bool should_notify =
      !GetValue(key, &initial_value) || (*initial_value != value);
  {
    base::AutoReset<bool> setting_prefs(&is_setting_prefs_, true);
    if (ShouldSetValueInAccountStore(key)) {
      if (IsPrefKeyMergeable(key)) {
        auto [new_local_value, new_account_value] =
            UnmergeValue(key, std::move(value), flags);
        account_pref_store_->SetValue(key, std::move(new_account_value), flags);
        local_pref_store_->SetValue(key, std::move(new_local_value), flags);
      } else {
        account_pref_store_->SetValue(key, value.Clone(), flags);
        local_pref_store_->SetValue(key, std::move(value), flags);
      }
    } else {
      local_pref_store_->SetValue(key, std::move(value), flags);
    }
  }
  if (should_notify) {
    for (PrefStore::Observer& observer : observers_) {
      observer.OnPrefValueChanged(key);
    }
  }
}
void DualLayerUserPrefStore::RemoveValue(std::string_view key, uint32_t flags) {
  // Only proceed if the pref exists.
  if (!GetValue(key, nullptr)) {
    return;
  }
  {
    base::AutoReset<bool> setting_prefs(&is_setting_prefs_, true);
    local_pref_store_->RemoveValue(key, flags);
    if (ShouldSetValueInAccountStore(key)) {
      account_pref_store_->RemoveValue(key, flags);
    }
  }
  // Remove from the list of merge prefs if exists.
  merged_prefs_.RemoveValue(key);
  for (PrefStore::Observer& observer : observers_) {
    observer.OnPrefValueChanged(key);
  }
}
bool DualLayerUserPrefStore::GetMutableValue(std::string_view key,
                                             base::Value** result) {
  if (!ShouldGetValueFromAccountStore(key)) {
    return local_pref_store_->GetMutableValue(key, result);
  }
  base::Value* local_value = nullptr;
  local_pref_store_->GetMutableValue(key, &local_value);
  base::Value* account_value = nullptr;
  account_pref_store_->GetMutableValue(key, &account_value);
  if (!account_value && !local_value) {
    // Pref doesn't exist.
    return false;
  }
  if (result) {
    // Note: Any changes to the returned Value will only directly take effect
    // in the underlying store. However, callers of this method are required to
    // call ReportValueChanged() once they're done modifying it, and that
    // propagates the change to all the underlying stores.
    // If pref exists it both stores, create a merged pref.
    if (account_value && local_value) {
      *result = MaybeMerge(key, *local_value, *account_value);
      CHECK(*result);
    } else if (account_value) {
      *result = account_value;
    } else {
      *result = local_value;
    }
  }
  return true;
}
void DualLayerUserPrefStore::ReportValueChanged(std::string_view key,
                                                uint32_t flags) {
  {
    base::AutoReset<bool> setting_prefs(&is_setting_prefs_, true);
    if (ShouldSetValueInAccountStore(key)) {
      const base::Value* new_value = nullptr;
      // In case a merged value was updated, it would exist in `merged_prefs_`.
      // Else, get the new value from whichever store has it and copy it to the
      // other one.
      if (merged_prefs_.GetValue(key, &new_value)) {
        auto [new_local_value, new_account_value] =
            UnmergeValue(key, new_value->Clone(), flags);
        account_pref_store_->SetValueSilently(key, std::move(new_account_value),
                                              flags);
        local_pref_store_->SetValueSilently(key, std::move(new_local_value),
                                            flags);
      } else if (account_pref_store_->GetValue(key, &new_value)) {
        local_pref_store_->SetValueSilently(key, new_value->Clone(), flags);
      } else if (local_pref_store_->GetValue(key, &new_value)) {
        account_pref_store_->SetValueSilently(key, new_value->Clone(), flags);
      }
      // It is possible that the pref just doesn't exist (anymore).
    }
    // Forward the ReportValueChanged() call to the underlying stores, so they
    // can notify their own observers.
    local_pref_store_->ReportValueChanged(key, flags);
    if (ShouldSetValueInAccountStore(key)) {
      account_pref_store_->ReportValueChanged(key, flags);
    }
  }
  for (PrefStore::Observer& observer : observers_) {
    observer.OnPrefValueChanged(key);
  }
}
void DualLayerUserPrefStore::SetValueSilently(std::string_view key,
                                              base::Value value,
                                              uint32_t flags) {
  if (ShouldSetValueInAccountStore(key)) {
    if (IsPrefKeyMergeable(key)) {
      auto [new_local_value, new_account_value] =
          UnmergeValue(key, std::move(value), flags);
      account_pref_store_->SetValueSilently(key, std::move(new_account_value),
                                            flags);
      local_pref_store_->SetValueSilently(key, std::move(new_local_value),
                                          flags);
    } else {
      account_pref_store_->SetValueSilently(key, value.Clone(), flags);
      local_pref_store_->SetValueSilently(key, std::move(value), flags);
    }
  } else {
    local_pref_store_->SetValueSilently(key, std::move(value), flags);
  }
}
void DualLayerUserPrefStore::RemoveValuesByPrefixSilently(
    std::string_view prefix) {
  local_pref_store_->RemoveValuesByPrefixSilently(prefix);
  // RemoveValuesByPrefixSilently() is not used for the account store since it
  // will remove values which are not being synced yet(for e.g. prefs behind
  // history opt-in). Instead, each pref in the account store is checked and
  // removed if it is writeable right now.
  {
    base::AutoReset<bool> setting_prefs(&is_setting_prefs_, true);
    // Clear all synced preferences with the prefix from the account store.
    for (const std::string& pref_name : GetPrefNamesInAccountStore()) {
      if (base::StartsWith(pref_name, prefix) &&
          ShouldSetValueInAccountStore(pref_name)) {
        account_pref_store_->RemoveValue(
            pref_name, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
      }
    }
  }
  // Remove from the list of merged prefs if exists.
  merged_prefs_.ClearWithPrefix(prefix);
}
bool DualLayerUserPrefStore::ReadOnly() const {
  return local_pref_store_->ReadOnly() || account_pref_store_->ReadOnly();
}
PersistentPrefStore::PrefReadError DualLayerUserPrefStore::GetReadError()
    const {
  if (auto local_prefs_read_error = local_pref_store_->GetReadError();
      local_prefs_read_error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
    return local_prefs_read_error;
  }
  return account_pref_store_->GetReadError();
}
PersistentPrefStore::PrefReadError DualLayerUserPrefStore::ReadPrefs() {
  // Call ReadPrefs() on both stores before reporting error.
  auto local_prefs_read_error = local_pref_store_->ReadPrefs();
  auto account_prefs_read_error = account_pref_store_->ReadPrefs();
  if (local_prefs_read_error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
    return local_prefs_read_error;
  }
  return account_prefs_read_error;
}
void DualLayerUserPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
  // The store is expected to take ownership of `error_delegate`, thus it's not
  // valid to forward the same to the two underlying stores. Instead, if any
  // error occurs, it's reported in OnInitializationCompleted() handle.
  read_error_delegate_.emplace(error_delegate);
  local_pref_store_->ReadPrefsAsync(nullptr);
  account_pref_store_->ReadPrefsAsync(nullptr);
}
void DualLayerUserPrefStore::CommitPendingWrite(
    base::OnceClosure reply_callback,
    base::OnceClosure synchronous_done_callback) {
  // A BarrierClosure will run its callback wherever the last instance of the
  // returned wrapper is invoked. As such it is guaranteed to respect the reply
  // vs synchronous semantics assuming `local_pref_store_` and
  // `account_pref_store_` honor it.
  static constexpr int kNumStores = 2;
  base::RepeatingClosure reply_callback_wrapper =
      reply_callback
          ? base::BarrierClosure(kNumStores, std::move(reply_callback))
          : base::RepeatingClosure();
  base::RepeatingClosure synchronous_callback_wrapper =
      synchronous_done_callback
          ? base::BarrierClosure(kNumStores,
                                 std::move(synchronous_done_callback))
          : base::RepeatingClosure();
  local_pref_store_->CommitPendingWrite(reply_callback_wrapper,
                                        synchronous_callback_wrapper);
  account_pref_store_->CommitPendingWrite(reply_callback_wrapper,
                                          synchronous_callback_wrapper);
}
void DualLayerUserPrefStore::SchedulePendingLossyWrites() {
  local_pref_store_->SchedulePendingLossyWrites();
  account_pref_store_->SchedulePendingLossyWrites();
}
void DualLayerUserPrefStore::OnStoreDeletionFromDisk() {
  local_pref_store_->OnStoreDeletionFromDisk();
  account_pref_store_->OnStoreDeletionFromDisk();
}
bool DualLayerUserPrefStore::ShouldSetValueInAccountStore(
    std::string_view key) const {
  // A preference `key` is added to account store only if it is syncable,  the
  // corresponding pref type is active, and falls under the current user
  // consent, i.e. "privacy-sensitive" prefs require history opt-in.
  // Never write to the account store if it's not read from the account store.
  if (!ShouldGetValueFromAccountStore(key)) {
    return false;
  }
  auto metadata = pref_model_associator_client_->GetSyncablePrefsDatabase()
                      .GetSyncablePrefMetadata(key);
  // Checks if the pref type is active.
  if (!active_types_.contains(metadata->data_type()) &&
      // Checks if the pref already exists in the account store.
      // This is to handle cases where a pref might pre-exist before sync is
      // initialized and the type is marked as active.
      !account_pref_store_->GetValue(key, nullptr)) {
    return false;
  }
  return true;
}
bool DualLayerUserPrefStore::ShouldGetValueFromAccountStore(
    std::string_view key) const {
  // A preference `key` is queried from account store only if it is syncable and
  // falls under the current user consent, i.e. "privacy-sensitive" prefs
  // require history opt-in.
  // Note: There is no check if the pref type is active because they are
  // determined only after the Sync machinery is initialized, but account-store
  // values need to be applied even before that.
  if (!pref_model_associator_client_) {
    // Safer this way.
    return false;
  }
  auto metadata = pref_model_associator_client_->GetSyncablePrefsDatabase()
                      .GetSyncablePrefMetadata(key);
  // Checks if the pref is a syncable pref.
  if (!metadata.has_value()) {
    return false;
  }
  // Checks if the pref requires a history opt-in.
  if (metadata->is_history_opt_in_required() && !IsHistorySyncEnabled()) {
    return false;
  }
  // Priority pref type is always active. This adds check to avoid syncing them
  // if the user toggle is off. This however skips all the allowlisted priority
  // prefs.
  if (base::FeatureList::IsEnabled(
          syncer::kSyncSupportAlwaysSyncingPriorityPreferences) &&
      metadata->data_type() == syncer::PRIORITY_PREFERENCES &&
      !GetInterestingUserSelectedTypes().Has(
          syncer::UserSelectableType::kPreferences) &&
      !pref_model_associator_client_->GetSyncablePrefsDatabase()
           .IsPreferenceAlwaysSyncing(key)) {
    return false;
  }
  return true;
}
void DualLayerUserPrefStore::EnableType(syncer::DataType data_type) {
  CHECK(data_type == syncer::PREFERENCES ||
        data_type == syncer::PRIORITY_PREFERENCES
#if BUILDFLAG(IS_CHROMEOS)
        || data_type == syncer::OS_PREFERENCES ||
        data_type == syncer::OS_PRIORITY_PREFERENCES
#endif
  );
  active_types_.insert(data_type);
}
void DualLayerUserPrefStore::DisableTypeAndClearAccountStore(
    syncer::DataType data_type) {
  CHECK(data_type == syncer::PREFERENCES ||
        data_type == syncer::PRIORITY_PREFERENCES
#if BUILDFLAG(IS_CHROMEOS)
        || data_type == syncer::OS_PREFERENCES ||
        data_type == syncer::OS_PRIORITY_PREFERENCES
#endif
  );
  active_types_.erase(data_type);
  if (!pref_model_associator_client_) {
    // No pref is treated as syncable in this case. No need to clear the account
    // store.
    return;
  }
  // Clear all synced preferences from the account store.
  for (const std::string& pref_name : GetPrefNamesInAccountStore()) {
    std::optional<SyncablePrefMetadata> metadata =
        pref_model_associator_client_->GetSyncablePrefsDatabase()
            .GetSyncablePrefMetadata(pref_name);
    CHECK(metadata.has_value());
    if (metadata->data_type() != data_type) {
      continue;
    }
    const base::Value* value = nullptr;
    // Should only notify observers if the effective value changes.
    // Note: A notification is still sent if a pref goes from an
    // explicitly-set value to an equal default value.
    // Note: If the pref requires history opt-in, but history sync is
    // disabled, GetValue() will not return the account value, and in case
    // no value for the pref exists in the local store, no notification should
    // be sent out.
    bool should_notify = GetValue(pref_name, &value);
    if (const base::Value* local_value = nullptr;
        value && local_pref_store_->GetValue(pref_name, &local_value)) {
      should_notify = (*local_value != *value);
    }
    {
      base::AutoReset<bool> setting_prefs(&is_setting_prefs_, true);
      // The write flags only affect persistence, and the default flag is the
      // safer choice.
      account_pref_store_->RemoveValue(
          pref_name, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
      merged_prefs_.RemoveValue(pref_name);
    }
    if (should_notify) {
      for (PrefStore::Observer& observer : observers_) {
        observer.OnPrefValueChanged(pref_name);
      }
    }
  }
  if (active_types_.empty()) {
    // Clear the account store of any garbage value without notifications. This
    // can happen if a previously syncable pref was persisted to the account
    // store but is no longer syncable.
    // TODO(crbug.com/40067768): Look into if the garbage values can cleared on
    // browser startup.
    // Since there's no direct way to clear the pref store or get a list of all
    // keys (because of the dotted paths) and `RemoveValuesByPrefixSilently("")`
    // is disallowed, the following workaround is used to clear the store.
    for (auto [key, value] : account_pref_store_->GetValues()) {
      account_pref_store_->RemoveValuesByPrefixSilently(key);
    }
    // Clear the user selected types pref in the local store.
    SetInterestingUserSelectedTypes(syncer::UserSelectableTypeSet());
  }
}
bool DualLayerUserPrefStore::IsPrefKeyMergeable(std::string_view key) const {
  if (!pref_model_associator_client_) {
    return false;
  }
  const auto& syncable_prefs_database =
      pref_model_associator_client_->GetSyncablePrefsDatabase();
  return syncable_prefs_database.IsPreferenceSyncable(key) &&
         syncable_prefs_database.IsPreferenceMergeable(key);
}
const base::Value* DualLayerUserPrefStore::MaybeMerge(
    std::string_view pref_name,
    const base::Value& local_value,
    const base::Value& account_value) const {
  // Return the account value if `pref_name` is not mergeable.
  if (!IsPrefKeyMergeable(pref_name)) {
    return &account_value;
  }
  // Note: The merged value is evaluated every time and not re-used from
  // `merged_prefs_`. This is to:
  // 1. Handle the cases where SetValueSilently() or
  // RemoveValueByPrefixSilently() is called on the underlying stores directly,
  // without a corresponding call to ReportValueChanged().
  // 2. Avoid removing the entry from `merged_prefs_` every time pref is
  // updated.
  base::Value merged_value =
      helper::MergePreference(pref_model_associator_client_.get(), pref_name,
                              local_value, account_value);
  // Add to `merged_prefs_` only if value doesn't already exist. This is done
  // because the previously returned value might be in use and replacing the
  // value would be risky - multiple successive calls to the getter shouldn't
  // invalidate previous results.
  if (base::Value* original_value = nullptr;
      !merged_prefs_.GetValue(pref_name, &original_value) ||
      *original_value != merged_value) {
    merged_prefs_.SetValue(pref_name, std::move(merged_value));
  }
  const base::Value* merged_pref = nullptr;
  merged_prefs_.GetValue(pref_name, &merged_pref);
  DCHECK(merged_pref);
  return merged_pref;
}
base::Value* DualLayerUserPrefStore::MaybeMerge(std::string_view pref_name,
                                                base::Value& local_value,
                                                base::Value& account_value) {
  // Doing const_cast should be safe as ultimately the value being pointed to is
  // a non-const object.
  return const_cast<base::Value*>(
      std::as_const(*this).MaybeMerge(pref_name, local_value, account_value));
}
std::pair<base::Value, base::Value> DualLayerUserPrefStore::UnmergeValue(
    std::string_view pref_name,
    base::Value value,
    uint32_t flags) const {
  CHECK(ShouldSetValueInAccountStore(pref_name));
  // Note: There is no "standard" unmerging logic for list or scalar prefs.
  // TODO(crbug.com/40256874): Allow support for custom unmerge logic.
  if (pref_model_associator_client_->GetSyncablePrefsDatabase()
          .GetSyncablePrefMetadata(pref_name)
          ->merge_behavior() == MergeBehavior::kMergeableDict) {
    // Per crbug.com/1430854, it is possible for the value to not be of dict
    // type. However, in this case, whatever is the type of `value` it's bound
    // to be correct, as UnmergeValue() is called by setters which in turn are
    // only called after a type check.
    if (value.is_dict()) {
      base::Value::Dict local_dict;
      if (const base::Value* local_dict_value = nullptr;
          local_pref_store_->GetValue(pref_name, &local_dict_value)) {
        // It is assumed that the local store cannot contain value of incorrect
        // type.
        local_dict = local_dict_value->GetDict().Clone();
      }
      base::Value::Dict account_dict;
      if (const base::Value* account_dict_value = nullptr;
          account_pref_store_->GetValue(pref_name, &account_dict_value)) {
        // It is assumed that the account store cannot contain value of
        // incorrect type.
        account_dict = account_dict_value->GetDict().Clone();
      }
      auto [new_local_dict, new_account_dict] = helper::UnmergeDictionaryValues(
          std::move(value).TakeDict(), local_dict, account_dict);
      // Note: This would still return an empty dict even if the pref didn't
      // exist in either of the stores. This should however be okay since no
      // actual pref value is leaked to the other.
      return {base::Value(std::move(new_local_dict)),
              base::Value(std::move(new_account_dict))};
    } else {
      DLOG(ERROR) << pref_name
                  << " marked as a mergeable dict pref but is of type "
                  << value.type();
    }
  }
  // Directly pass the new value as both the local value and the account value
  // for prefs with no specific merge logic.
  base::Value new_account_value(value.Clone());
  base::Value new_local_value(std::move(value));
  return {std::move(new_local_value), std::move(new_account_value)};
}
bool DualLayerUserPrefStore::IsInitializationSuccessful() const {
  return local_pref_store_observer_.initialization_succeeded() &&
         account_pref_store_observer_.initialization_succeeded();
}
std::vector<std::string> DualLayerUserPrefStore::GetPrefNamesInAccountStore()
    const {
  std::vector<std::string> keys;
  if (!pref_model_associator_client_) {
    return keys;
  }
  // GetValues() returns a dict which is set using SetByDottedPaths(). That
  // means, a key "a.b.c" is presented as: `{'a': {'b': {'c': ... }}}`. This
  // util recurses over the nested dicts with keys being joined with a dot, till
  // the string forms a valid pref name, for eg. it will recurse with keys, "a",
  // "a.b", and then "a.b.c" which was the original key.
  auto recurse_and_insert = [&](const std::string& key,
                                const base::Value& value,
                                auto& recurse_and_insert_ref) -> void {
    // Checks if `key` is a pref name using syncable pref database. This is
    // different from ShouldSetValueInAccountStore() which checks whether or not
    // a pref should synced right now based on enabled DataTypes.
    if (pref_model_associator_client_->GetSyncablePrefsDatabase()
            .IsPreferenceSyncable(key)) {
      keys.push_back(key);
    } else if (value.is_dict()) {
      for (auto [k, v] : value.GetDict()) {
        recurse_and_insert_ref(key + "." + k, v, recurse_and_insert_ref);
      }
    }
  };
  for (auto [key, value] : account_pref_store_->GetValues()) {
    recurse_and_insert(key, value, recurse_and_insert);
  }
  return keys;
}
base::flat_set<syncer::DataType> DualLayerUserPrefStore::GetActiveTypesForTest()
    const {
  return active_types_;
}
bool DualLayerUserPrefStore::IsHistorySyncEnabled() const {
  return GetInterestingUserSelectedTypes().Has(
      syncer::UserSelectableType::kHistory);
}
bool DualLayerUserPrefStore::IsHistorySyncEnabledForTest() const {
  return IsHistorySyncEnabled();
}
void DualLayerUserPrefStore::SetIsHistorySyncEnabledForTest(
    bool is_history_sync_enabled) {
  syncer::UserSelectableTypeSet user_selected_types =
      GetInterestingUserSelectedTypes();
  if (is_history_sync_enabled) {
    user_selected_types.Put(syncer::UserSelectableType::kHistory);
  } else {
    user_selected_types.Remove(syncer::UserSelectableType::kHistory);
  }
  SetUserSelectedTypesForTest(user_selected_types);
}
syncer::UserSelectableTypeSet
DualLayerUserPrefStore::GetUserSelectedTypesForTest() const {
  return GetInterestingUserSelectedTypes();
}
void DualLayerUserPrefStore::SetUserSelectedTypesForTest(
    syncer::UserSelectableTypeSet user_selected_types) {
  SetInterestingUserSelectedTypes(user_selected_types);
}
void DualLayerUserPrefStore::SetInterestingUserSelectedTypes(
    syncer::UserSelectableTypeSet user_selected_types) {
  // This is stored in the local pref store for early availability to be able to
  // decide whether to expose values of account priority prefs and
  // history-scoped prefs.
  CHECK(kInterestingUserSelectableTypes.HasAll(user_selected_types));
  local_pref_store_->SetValueSilently(
      kUserSelectedTypesPrefName,
      base::Value(syncer::UserSelectableTypeSetToValueList(user_selected_types)),
      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
}
syncer::UserSelectableTypeSet
DualLayerUserPrefStore::GetInterestingUserSelectedTypes() const {
  const base::Value* value = nullptr;
  // Load the user selected types from the local pref store. This allows for
  // persistence and early availability.
  if (!local_pref_store_->GetValue(kUserSelectedTypesPrefName, &value) ||
      !value->is_list()) {
    return syncer::UserSelectableTypeSet();
  }
  return base::Intersection(syncer::ValueListToUserSelectableTypeSet(value->GetList()),
                            kInterestingUserSelectableTypes);
}
void DualLayerUserPrefStore::OnSyncServiceInitialized(
    syncer::SyncService* sync_service) {
  sync_service->AddObserver(this);
  // `sync_service` init should be considered as a state change.
  OnStateChanged(sync_service);
}
void DualLayerUserPrefStore::OnStateChanged(syncer::SyncService* sync_service) {
  syncer::UserSelectableTypeSet user_selected_types =
      sync_service->GetUserSettings()->GetSelectedTypes();
  // Only retain the concerning types.
  user_selected_types.RetainAll(kInterestingUserSelectableTypes);
  if (user_selected_types == GetInterestingUserSelectedTypes()) {
    return;
  }
  if (!pref_model_associator_client_) {
    SetInterestingUserSelectedTypes(user_selected_types);
    return;
  }
  // Store the old values for account prefs in a map and only inform the
  // observers if the effective values change.
  // Note: std::optional is used as the value type since it makes the
  // comparison with the new values easier.
  std::map<std::string, std::optional<base::Value>> old_values;
  for (const std::string& pref_name : GetPrefNamesInAccountStore()) {
    auto metadata = pref_model_associator_client_->GetSyncablePrefsDatabase()
                        .GetSyncablePrefMetadata(pref_name);
    CHECK(metadata.has_value());
    if (const base::Value* value = nullptr; GetValue(pref_name, &value)) {
      old_values.emplace(pref_name, value->Clone());
    } else {
      // Put in std::nullopt to mark pref not existing in the store. This
      // helps avoid an extra call to GetPrefNamesInAccount() later.
      old_values.emplace(pref_name, std::nullopt);
    }
  }
  SetInterestingUserSelectedTypes(user_selected_types);
  // The sync state change might have changed the effective value. Compare the
  // old and new values and notify the observers if they change.
  for (const auto& [pref_name, old_value] : old_values) {
    std::optional<base::Value> new_value;
    if (const base::Value* value = nullptr; GetValue(pref_name, &value)) {
      new_value = value->Clone();
    }
    // Only notify the observers if the effective value is changing.
    if (old_value != new_value) {
      for (PrefStore::Observer& observer : observers_) {
        observer.OnPrefValueChanged(pref_name);
      }
    }
  }
}
void DualLayerUserPrefStore::OnSyncShutdown(syncer::SyncService* sync_service) {
  // Pref service and hence the pref store outlives sync service.
  sync_service->RemoveObserver(this);
}
void DualLayerUserPrefStore::SetValueInAccountStoreOnly(std::string_view key,
                                                        base::Value value,
                                                        uint32_t flags) {
  const base::Value* initial_value = nullptr;
  // Only notify if the effective value actually changes.
  bool should_notify =
      !GetValue(key, &initial_value) || (*initial_value != value);
  {
    base::AutoReset<bool> setting_prefs(&is_setting_prefs_, true);
    account_pref_store_->SetValue(key, std::move(value), flags);
  }
  if (should_notify) {
    for (PrefStore::Observer& observer : observers_) {
      observer.OnPrefValueChanged(key);
    }
  }
}
bool DualLayerUserPrefStore::HasReadErrorDelegate() const {
  return read_error_delegate_.has_value();
}
}  // namespace sync_preferences
 |