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