Chromium 书签加载过程分析c++

一、书签存储路径:

%localappdata%\Chromium\User Data\Default\Bookmarks

%localappdata%\Chromium\User Data\Default\Bookmarks.bak 【备份文件】

本机测试存储的Bookmarks文件如下(未加密的可以直接打开):

{
   "checksum": "edefd2b00f017cd9e3dcb3c0d194d950",
   "roots": {
      "bookmark_bar": {
         "children": [ {
            "date_added": "13372945710911965",
            "date_last_used": "0",
            "guid": "bf9fbd31-8ce1-48a0-b5f9-7ad492da0c7d",
            "id": "7",
            "meta_info": {
               "power_bookmark_meta": ""
            },
            "name": "百度一下,你就知道",
            "type": "url",
            "url": "https://www.baidu.com/"
         } ],
         "date_added": "13372779889012656",
         "date_last_used": "0",
         "date_modified": "13372945725936476",
         "guid": "0bc5d13f-2cba-5d74-951f-3f233fe6c908",
         "id": "1",
         "name": "书签栏",
         "type": "folder"
      },
      "other": {
         "children": [  ],
         "date_added": "13372779889012676",
         "date_last_used": "0",
         "date_modified": "13372945710911965",
         "guid": "82b081ec-3dd3-529c-8475-ab6c344590dd",
         "id": "2",
         "name": "其他书签",
         "type": "folder"
      },
      "synced": {
         "children": [  ],
         "date_added": "13372779889012687",
         "date_last_used": "0",
         "date_modified": "0",
         "guid": "4cf2e351-0e85-532b-bb37-df045d8f8d0f",
         "id": "3",
         "name": "移动设备书签",
         "type": "folder"
      }
   },
   "version": 1
}

二、浏览器启动过程加载书签过程:

1、bookmark_model_factory.cc文件BuildBookmarkModel函数

    调用BookmarkModel::Load()进行书签加载。

namespace {

using bookmarks::BookmarkModel;

std::unique_ptr<KeyedService> BuildBookmarkModel(
    content::BrowserContext* context) {
  Profile* profile = Profile::FromBrowserContext(context);
  auto bookmark_model =
      std::make_unique<BookmarkModel>(std::make_unique<ChromeBookmarkClient>(
          profile, ManagedBookmarkServiceFactory::GetForProfile(profile),
          LocalOrSyncableBookmarkSyncServiceFactory::GetForProfile(profile),
          AccountBookmarkSyncServiceFactory::GetForProfile(profile),
          BookmarkUndoServiceFactory::GetForProfile(profile)));
#if defined(TOOLKIT_VIEWS)
  // BookmarkExpandedStateTracker depends on the loading event, so this
  // coupling must happen before the loading happens.
  BookmarkExpandedStateTrackerFactory::GetForProfile(profile)->Init(
      bookmark_model.get());
#endif
  //传入user_data路径
  bookmark_model->Load(profile->GetPath(),
                       bookmarks::StorageType::kLocalOrSyncable);
  BookmarkUndoServiceFactory::GetForProfile(profile)
      ->StartObservingBookmarkModel(bookmark_model.get());
  return bookmark_model;
}

}  // namespace

2、进入bookmark_model.cc BookmarkModel::Load函数其中:

     BookmarkStorage store_ 用来存储备份书签
      ModelLoader model_loader_用来加载和解析书签数据。

void BookmarkModel::Load(const base::FilePath& profile_path,
                         StorageType storage_type) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  // If the store is non-null, it means Load was already invoked. Load should
  // only be invoked once.
  DCHECK(!store_);

  const base::FilePath file_path =
      GetStorageFilePath(profile_path, storage_type);
 //BookmarkStorage 用来存储备份书签
  store_ = std::make_unique<BookmarkStorage>(this, file_path);
  // Creating ModelLoader schedules the load on a backend task runner.
//ModelLoader 用来加载和解析书签数据
  model_loader_ = ModelLoader::Create(
      file_path, std::make_unique<BookmarkLoadDetails>(client_.get()),
      base::BindOnce(&BookmarkModel::DoneLoading, AsWeakPtr()));
}

3、看下ModelLoader::Create加载书签过程(components\bookmarks\browser\model_loader.cc)

// static
scoped_refptr<ModelLoader> ModelLoader::Create(
    const base::FilePath& file_path,
    std::unique_ptr<BookmarkLoadDetails> details,
    LoadCallback callback) {
  // Note: base::MakeRefCounted is not available here, as ModelLoader's
  // constructor is private.
  auto model_loader = base::WrapRefCounted(new ModelLoader());
  model_loader->backend_task_runner_ =
      base::ThreadPool::CreateSequencedTaskRunner(
          {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
           base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});

  model_loader->backend_task_runner_->PostTaskAndReplyWithResult(
      FROM_HERE,
      base::BindOnce(&ModelLoader::DoLoadOnBackgroundThread, model_loader,
                     file_path, std::move(details)),
      std::move(callback));
  return model_loader;
}
std::unique_ptr<BookmarkLoadDetails> ModelLoader::DoLoadOnBackgroundThread(
    const base::FilePath& file_path,
    std::unique_ptr<BookmarkLoadDetails> details) {
  LoadBookmarks(file_path, details.get());
  history_bookmark_model_ = details->url_index();
  loaded_signal_.Signal();
  return details;
}

执行顺序:ModelLoader::Create->DoLoadOnBackgroundThread->LoadBookmarks

看下LoadBookmarks函数定义:

namespace {

// Loads the bookmarks. This is intended to be called on the background thread.
// Updates state in |details| based on the load.
void LoadBookmarks(const base::FilePath& path,
                   BookmarkLoadDetails* details) {
  bool bookmark_file_exists = base::PathExists(path);
  if (bookmark_file_exists) {
    // Titles may end up containing invalid utf and we shouldn't throw away
    // all bookmarks if some titles have invalid utf.
    JSONFileValueDeserializer deserializer(
        path, base::JSON_REPLACE_INVALID_CHARACTERS);
    std::unique_ptr<base::Value> root_value =
        deserializer.Deserialize(nullptr, nullptr);

    if (!root_value) {
      // The bookmark file exists but was not deserialized.
    } else if (const auto* root_dict = root_value->GetIfDict()) {
      int64_t max_node_id = 0;
      std::string sync_metadata_str;
      BookmarkCodec codec;
      codec.Decode(*root_dict, details->bb_node(), details->other_folder_node(),
                   details->mobile_folder_node(), &max_node_id,
                   &sync_metadata_str);
      details->set_sync_metadata_str(std::move(sync_metadata_str));
      details->set_max_id(std::max(max_node_id, details->max_id()));
      details->set_computed_checksum(codec.computed_checksum());
      details->set_stored_checksum(codec.stored_checksum());
      details->set_ids_reassigned(codec.ids_reassigned());
      details->set_uuids_reassigned(codec.uuids_reassigned());
      details->set_model_meta_info_map(codec.model_meta_info_map());
    }
  }

  details->LoadManagedNode();

  // Building the indices can take a while so it's done on the background
  // thread.
  details->CreateIndices();

  UrlLoadStats stats = details->url_index()->ComputeStats();
  metrics::RecordUrlLoadStatsOnProfileLoad(stats);

  int64_t file_size_bytes;
  if (bookmark_file_exists && base::GetFileSize(path, &file_size_bytes)) {
    metrics::RecordFileSizeAtStartup(file_size_bytes);
    metrics::RecordAverageNodeSizeAtStartup(
        stats.total_url_bookmark_count == 0
            ? 0
            : file_size_bytes / stats.total_url_bookmark_count);
  }
}

}  // namespace

LoadBookmarks函数里面读取boolmarks文件进行解析完毕运行callback

BookmarkModel::DoneLoading在通知观察者加载书签完毕。

 // Notify our direct observers.
  for (BookmarkModelObserver& observer : observers_) {
    observer.BookmarkModelLoaded(this, details->ids_reassigned());
  }

void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(details);
  DCHECK(!loaded_);

  next_node_id_ = details->max_id();
  if (details->computed_checksum() != details->stored_checksum() ||
      details->ids_reassigned() || details->uuids_reassigned()) {
    // If bookmarks file changed externally, the IDs may have changed
    // externally. In that case, the decoder may have reassigned IDs to make
    // them unique. So when the file has changed externally, we should save the
    // bookmarks file to persist such changes. The same applies if new UUIDs
    // have been assigned to bookmarks.
    if (store_) {
      store_->ScheduleSave();
    }
  }

  titled_url_index_ = details->owned_titled_url_index();
  uuid_index_ = details->owned_uuid_index();
  url_index_ = details->url_index();
  root_ = details->root_node();
  // See declaration for details on why `owned_root_` is reset.
  owned_root_.reset();
  bookmark_bar_node_ = details->bb_node();
  other_node_ = details->other_folder_node();
  mobile_node_ = details->mobile_folder_node();

  // TODO(crbug.com/1494120): Load nodes for account storage as well.

  titled_url_index_->SetNodeSorter(
      std::make_unique<TypedCountSorter>(client_.get()));
  // Sorting the permanent nodes has to happen on the main thread, so we do it
  // here, after loading completes.
  root_->SortChildren(VisibilityComparator(client_.get()));

  root_->SetMetaInfoMap(details->model_meta_info_map());

  loaded_ = true;
  client_->DecodeBookmarkSyncMetadata(
      details->sync_metadata_str(),
      store_ ? base::BindRepeating(&BookmarkStorage::ScheduleSave,
                                   base::Unretained(store_.get()))
             : base::DoNothing());

  const base::TimeDelta load_duration =
      base::TimeTicks::Now() - details->load_start();
  metrics::RecordTimeToLoadAtStartup(load_duration,
                                     client_->GetStorageStateForUma());

  // Notify our direct observers.
  for (BookmarkModelObserver& observer : observers_) {
    observer.BookmarkModelLoaded(this, details->ids_reassigned());
  }
}

4、看下观察者定义:components\bookmarks\browser\bookmark_model_observer.h


// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_MODEL_OBSERVER_H_
#define COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_MODEL_OBSERVER_H_

#include <set>

#include <stddef.h>

#include "base/observer_list_types.h"

class GURL;

namespace bookmarks {

class BookmarkModel;
class BookmarkNode;

// Observer for the BookmarkModel.
class BookmarkModelObserver : public base::CheckedObserver {
 public:
  BookmarkModelObserver(const BookmarkModelObserver&) = delete;
  BookmarkModelObserver& operator=(const BookmarkModelObserver&) = delete;

  // Invoked when the model has finished loading. |ids_reassigned| mirrors
  // that of BookmarkLoadDetails::ids_reassigned. See it for details.
  virtual void BookmarkModelLoaded(BookmarkModel* model,
                                   bool ids_reassigned) = 0;

  // Invoked from the destructor of the BookmarkModel.
  virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {}

  // Invoked when a node has moved.
  virtual void BookmarkNodeMoved(BookmarkModel* model,
                                 const BookmarkNode* old_parent,
                                 size_t old_index,
                                 const BookmarkNode* new_parent,
                                 size_t new_index) = 0;

  // Invoked when a node has been added. If the added node has any descendants,
  // BookmarkModel` will invoke `BookmarkNodeAdded` recursively for all these
  // descendants.
  // TODO(crbug.com/1440384): See if this should send only one notification,
  //                          for consistency with `BookmarkNodeRemoved`.
  //
  // `added_by_user` is true when a new bookmark was added by the user and false
  // when a node is added by sync or duplicated.
  virtual void BookmarkNodeAdded(BookmarkModel* model,
                                 const BookmarkNode* parent,
                                 size_t index,
                                 bool added_by_user) = 0;

  // Invoked prior to removing a node from the model. When a node is removed
  // it's descendants are implicitly removed from the model as
  // well. Notification is only sent for the node itself, not any
  // descendants. For example, if folder 'A' has the children 'A1' and 'A2',
  // model->Remove('A') generates a single notification for 'A'; no notification
  // is sent for 'A1' or 'A2'.
  //
  // |parent| the parent of the node that will be removed.
  // |old_index| the index of the node about to be removed in |parent|.
  // |node| is the node to be removed.
  virtual void OnWillRemoveBookmarks(BookmarkModel* model,
                                     const BookmarkNode* parent,
                                     size_t old_index,
                                     const BookmarkNode* node) {}

  // Invoked after a node has been removed from the model. Removing a node
  // implicitly removes all descendants. Notification is only sent for the node
  // that BookmarkModel::Remove() is invoked on. See description of
  // OnWillRemoveBookmarks() for details.
  //
  // |parent| the parent of the node that was removed.
  // |old_index| the index of the removed node in |parent| before it was
  // removed.
  // |node| the node that was removed.
  // |no_longer_bookmarked| contains the urls of any nodes that are no longer
  // bookmarked as a result of the removal.
  virtual void BookmarkNodeRemoved(
      BookmarkModel* model,
      const BookmarkNode* parent,
      size_t old_index,
      const BookmarkNode* node,
      const std::set<GURL>& no_longer_bookmarked) = 0;

  // Invoked before the title or url of a node is changed. Subsequent
  // BookmarkNodeChanged call guaranteed to contain the same BookmarkNode.
  virtual void OnWillChangeBookmarkNode(BookmarkModel* model,
                                        const BookmarkNode* node) {}

  // Invoked when the title or url of a node changes. Guaranteed to contain the
  // same BookmarkNode as the preceding OnWillChangeBookmark Node call.
  virtual void BookmarkNodeChanged(BookmarkModel* model,
                                   const BookmarkNode* node) = 0;

  // Invoked before the metainfo of a node is changed.
  virtual void OnWillChangeBookmarkMetaInfo(BookmarkModel* model,
                                            const BookmarkNode* node) {}

  // Invoked when the metainfo on a node changes.
  virtual void BookmarkMetaInfoChanged(BookmarkModel* model,
                                       const BookmarkNode* node) {}

  // Invoked when a favicon has been loaded or changed.
  virtual void BookmarkNodeFaviconChanged(BookmarkModel* model,
                                          const BookmarkNode* node) = 0;

  // Invoked before the direct children of |node| have been reordered in some
  // way, such as sorted.
  virtual void OnWillReorderBookmarkNode(BookmarkModel* model,
                                         const BookmarkNode* node) {}

  // Invoked when the children (just direct children, not descendants) of
  // |node| have been reordered in some way, such as sorted.
  virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
                                             const BookmarkNode* node) = 0;

  // Invoked before an extensive set of model changes is about to begin.
  // This tells UI intensive observers to wait until the updates finish to
  // update themselves.
  // These methods should only be used for imports and sync.
  // Observers should still respond to BookmarkNodeRemoved immediately,
  // to avoid holding onto stale node pointers.
  virtual void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {}

  // Invoked after an extensive set of model changes has ended.
  // This tells observers to update themselves if they were waiting for the
  // update to finish.
  virtual void ExtensiveBookmarkChangesEnded(BookmarkModel* model) {}

  // Invoked before all non-permanent bookmark nodes that are editable by
  // the user are removed.
  virtual void OnWillRemoveAllUserBookmarks(BookmarkModel* model) {}

  // Invoked when all non-permanent bookmark nodes that are editable by the
  // user have been removed.
  // |removed_urls| is populated with the urls which no longer have any
  // bookmarks associated with them.
  virtual void BookmarkAllUserNodesRemoved(
      BookmarkModel* model,
      const std::set<GURL>& removed_urls) = 0;

  // Invoked before a set of model changes that is initiated by a single user
  // action. For example, this is called a single time when pasting from the
  // clipboard before each pasted bookmark is added to the bookmark model.
  virtual void GroupedBookmarkChangesBeginning(BookmarkModel* model) {}

  // Invoked after a set of model changes triggered by a single user action has
  // ended.
  virtual void GroupedBookmarkChangesEnded(BookmarkModel* model) {}

 protected:
  BookmarkModelObserver() = default;
  ~BookmarkModelObserver() override = default;
};

}  // namespace bookmarks

#endif  // COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_MODEL_OBSERVER_H_

5、最后看下调试堆栈:

   

总结:

components\bookmarks\browser\bookmark_model.h 此文件里面是核心控制逻辑,书签的加载

添加删除排序都在此文件里面控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值