• 转chromeUI4


    PrefService

    和许多其他的程序一样,chrome也包含一系列本地配置文件,这些文件保存程序需要在重启后还能够记忆的参数或者其他数据。Chromium的配置文件存放在路径【C:Documents and SettingsUsernameLocal SettingsApplication DataChromiumUser DataDefault】。Chrome典型的配置文件格式如下:
    {

    … 省略 …

    "profile": {

    "exited_cleanly": true,

    "id": "not-signed-in",

    "name": "",

    "nickname": ""

    },

    "session": {

    "urls_to_restore_on_startup": [ ]

    }

    }

    chrome本地配置文件通过一个核心的类【chromecommonpref_service.cc】来实现,在这个类中,它调用解析器JSONStringValueSerializer【chromecommonpref_service.cc】将PrefService 结构中的内容转换成一个可写入文本文件的字符串。最后通过WriteFile函数【basefile_util_win.cc】将字符串写入文本。需要注意的是这个函数并不是UI线程调用的,而是用后台线程来实现。具体参见下列代码:
    【chromecommonpref_service.cc】

    DE>SaveLaterTask* task = new SaveLaterTask(pref_filename_, data);
    if (thread != NULL) {
    // We can use the background thread, it will take ownership of the task.

    thread->message_loop()->PostTask(FROM_HERE, task);
    

    } else {
    // In unit test mode, we have no background thread, just execute.

    task->Run();
    delete task;
    

    }DE>

    为了方便管理PrefService,chrome提供了一个ProfileManager类【chromerowserprofile_manager.h】和Profile 类【chromerowserprofile.h】。这里不做分析,因为这几个类并不通用。

    PrefService使用

    为了新建一个在路径为”C:Preferences”的配置文件,我们可以声明一个PrefService 实例:

    DE>PrefService * pService = new PrefService(L”C:Preferences”);DE>

    当需要往该配置文件增加一个参数时,可以参考下列步骤
    声明一个合适的类型,chrome提供了若干种类型,例如BooleanPrefMember、 IntegerPrefMember、 StringPrefMember等。当需要存取一个bool类型。可以声明一个BooleanPrefMember。具体的实现见【chromecommonpref_member.cc】。
    向prefService结构里注册一个pref变量,并提供默认值。每一个pref变量必须有一个名字,该名字对应于该变量在配置文件中的“路径”。pref名字可以直接输入。但是保险的做法是将所有pref的名字存放在一个统一的地方以方便管理。chrome的所有prefName存放在文件【chromecommonpref_names.h】中。perfName通过英语句号分割,每一节表示一层。例如perfName【L"general.luaguage.language"】在实际的配置文件的表现如下。
    {

    "general": {

    "luaguage": {

    "language": "zh-CN"

    }

    }

    }

    初始化这个类型。初始化时pref类型需要提供三个参数,该变量的名字,prefService的指针和一个回调。一般情况下,变量的名字和第二步注册的名字相同,prefService指针也和注册该pref变量使用的prefService一致。这一步的目的就是将一个本地变量和某一个全局的prefService中的某一个变量关联起来。既然他们是两个不同的变量(而不是两个指针指向同一个变量),那么就存在同步的问题。当prefService中的变量被其他线程偷偷的修改了怎么办呢,后面再分析。
    对这个类型进行读写操作。例如成员函数GetValue()和SetValue(value)。这两个函数对bool,int,string等类型都适用,底层使用很容易想到用模版类,如果研究过stl源码,这个其实是很容易理解。
    一般情况下,prefService总是作为一个全局变量存储在内存中,它在程序初始化时从磁盘读入数据,在程序退出时,将数据写入磁盘。很明显。如果程序中途崩溃或者断电等因素。这之前作出的配置改动都会丢失。貌似chrome有一个周期性将这些数据写入磁盘的机制,具体没去研究。
    当一个新的程序安装后,磁盘没有任何配置参数,但是每一个pref变量在注册到prefService时都指定了一个默认值,新程序即使用这个值来初始化程序。也许有人会注意到,程序运行一次以后磁盘还是没有写入任何东西,是不是没有在退出程序时写入磁盘啊?chrome对每一个pref变量会判断是否该修改,如果未修改,它实际上什么都不做。很显然,前面的情况是因为用户或者程序根本没有修改任何一个pref参数。

    Pref同步

    将配置参数封装成PrefMember等类的一个重要原因是支持实时同步。该类实际上使用
    了一个”OBSERVER”<观察者>设计模式。
    在PrefMember初始化时,它会将自己注册至赋值给自己的 PrefService对象,以便在信
    息发生变化时能够尽快得到通知。而外部应用同样可以在初始化pref变量注册一个回调,以便在该pref变量被其他人修改时及时得到通知。

    PrefService内部实现

    PrefService将所有从对应配置文件读取的信息存储在内部的一个【PreferenceSet prefs_】【typedef std::set<Preference*, PreferencePathComparator> PreferenceSet;】中, Preference则是封装了每一个pref变量的Name和value等信息:
    Preference类中的部分成员【chromecommonpref_service.h】

    DE>Value::ValueType type_;
    std::wstring name_;
    scoped_ptr default_value_;DE>

    Value这个类值得研究一下,它可用于表示所有类型,不过底层实现并不是模版类,而是继承和多态来实现。Value只不过是众多具体实现类的一个基类。
    chrome这一套pref机制具有很好的扩展性。当新的需要导致一个新的pref变量时,除了需要在【chromecommonpref_names.h】文件中增加一个pref名字以外,其他的处理都可以在“当地”进行。

    PathService

    前面提到,chrome包含若干配置文件。这些文件的路径怎么指定,直接在程序输入地址么,这并不是一个好的办法。chrome提供了一个PathService类【srcasepath_service.cc】。通过这个类的Get函数,其他模块可以很方便地获取一个Path(路径)。
    在PathService中,每一个Path都有一个唯一的PathID(int类型)。
    在pathService中,所有的path都存储在一个由结构 Provider构成的链表中,每一个Provider中包含一个ProviderFunc函数指针。当用户通过PathService的Get函数查询一个path时,PathService以此查询每一个Provider,而Provider由通过函数func来获得实际的path。

    DE>struct Provider {
    PathService::ProviderFunc func;
    struct Provider* next;
    ...
    bool is_static;
    };DE>

    为了获得更好的性能,chrome在PathService中内置了path cache。下面的 PathData结构存储了PathService的所有数据。 providers是Provider的首节点。 cache即上面提到的缓存.

    DE>struct PathData {
    Lock lock;
    PathMap cache; // Track mappings from path key to path value.

    PathSet overrides; // Track whether a path has been overridden.

    Provider* providers; DE>

    Chrome默认提供三个Provider。
    base_provider :【basepath_service.cc】
    base_provider_win :【basepath_service.cc】
    PathProvider :【chromecommonchrome_paths.cc】
    用户可以通过RegisterProvider函数【basepath_service.cc】注册自己的Provider。 PathProvider的注册代码如下:

    DE>void RegisterPathProvider() {
    PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
    }DE>

    自定义Provider

    如果用户需要注册自定义Provider,只需实现一个函数【 typedef bool (ProviderFunc)(int, FilePath)】。这个函数收到一个PathID。如果该ID在本函数内合法,则返回true,并且将Path通过第二个参数传回来。否则返回false。具体实现参考PathProvider函数【chromecommonchrome_paths.cc】。
    然后通过 PathService::RegisterProvider函数注册自己即可。

  • 相关阅读:
    【已解决】github中git push origin master出错:error: failed to push some refs to
    好记心不如烂笔头,ssh登录 The authenticity of host 192.168.0.xxx can't be established. 的问题
    THINKPHP 5.0目录结构
    thinkphp5.0入口文件
    thinkphp5.0 生命周期
    thinkphp5.0 架构
    Django template
    Django queryset
    Django model
    Python unittest
  • 原文地址:https://www.cnblogs.com/kevinzhwl/p/5276664.html
Copyright © 2020-2023  润新知