一、书签存储路径:
%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 此文件里面是核心控制逻辑,书签的加载
添加删除排序都在此文件里面控制。