注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

写着玩

Bob

 
 
 

日志

 
 
 
 

chrome UI 学习笔记4--PathService   

2009-12-01 16:13:51|  分类: Chrome |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

PrefService


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

{

省略 …

"profile": {

"exited_cleanly": true,

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

"name": "",

"nickname": ""

},

"session": {

"urls_to_restore_on_startup": [ ]

}

}


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

chrome\common\pref_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>


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



PrefService使用

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


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


当需要往该配置文件增加一个参数时,可以参考下列步骤

  1. 声明一个合适的类型,chrome提供了若干种类型,例如BooleanPrefMemberIntegerPrefMemberStringPrefMember等。当需要存取一个bool类型。可以声明一个BooleanPrefMember。具体的实现见【chrome\common\pref_member.cc】。

  2. prefService结构里注册一个pref变量,并提供默认值。每一个pref变量必须有一个名字,该名字对应于该变量在配置文件中的“路径”。pref名字可以直接输入。但是保险的做法是将所有pref的名字存放在一个统一的地方以方便管理。chrome的所有prefName存放在文件【chrome\common\pref_names.h】中。perfName通过英语句号分割,每一节表示一层。例如perfNameL"general.luaguage.language"】在实际的配置文件的表现如下。

  3. {

    "general": {

    "luaguage": {

    "language": "zh-CN"

    }

    }

    }

  4. 初始化这个类型。初始化时pref类型需要提供三个参数,该变量的名字,prefService的指针和一个回调。一般情况下,变量的名字和第二步注册的名字相同,prefService指针也和注册该pref变量使用的prefService一致。这一步的目的就是将一个本地变量和某一个全局的prefService中的某一个变量关联起来。既然他们是两个不同的变量(而不是两个指针指向同一个变量),那么就存在同步的问题。当prefService中的变量被其他线程偷偷的修改了怎么办呢,后面再分析。 <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } --> 

  5. 对这个类型进行读写操作。例如成员函数GetValue()SetValue(value)。这两个函数对boolintstring等类型都适用,底层使用很容易想到用模版类,如果研究过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变量的Namevalue等信息:

Preference类中的部分成员【chrome\common\pref_service.h


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


Value这个类值得研究一下,它可用于表示所有类型,不过底层实现并不是模版类,而是继承和多态来实现。Value只不过是众多具体实现类的一个基类。

chrome这一套pref机制具有很好的扩展性。当新的需要导致一个新的pref变量时,除了需要在【chrome\common\pref_names.h】文件中增加一个pref名字以外,其他的处理都可以在“当地”进行。



PathService

前面提到,chrome包含若干配置文件。这些文件的路径怎么指定,直接在程序输入地址么,这并不是一个好的办法。chrome提供了一个PathService类【src\base\path_service.cc】。通过这个类的Get函数,其他模块可以很方便地获取一个Path(路径)。

PathService中,每一个Path都有一个唯一的PathIDint类型)。

pathService中,所有的path都存储在一个由结构 Provider构成的链表中,每一个Provider中包含一个ProviderFunc函数指针。当用户通过PathServiceGet函数查询一个path时,PathService以此查询每一个Provider,而Provider由通过函数func来获得实际的path


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


为了获得更好的性能,chromePathService中内置了path cache。下面的 PathData结构存储了PathService的所有数据。 providersProvider的首节点。 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

  1. base_provider :【base\path_service.cc

  2. base_provider_win :【base\path_service.cc

  3. PathProvider :【chrome\common\chrome_paths.cc

用户可以通过RegisterProvider函数【base\path_service.cc】注册自己的ProviderPathProvider的注册代码如下:


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


自定义Provider

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

然后通过 PathService::RegisterProvider函数注册自己即可。

  评论这张
 
阅读(686)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017