Profile Architecture

 

Profile Architecture

This page details an ongoing design refactoring, started in January 2012.

Chromium has lots of features that hook into a Profile, a bundle of data about the current user and the current chrome session that can span multiple browser windows. When Chromium first started, the profile had only a few moving parts: the cookie jar, the history database, the bookmark database, and things to do with user preferences. In the three years of the Chromium Project, Profile became the join point for every feature, leading to things like Profile::GetInstantPromoCounter() or Proifle::GetHostContentSettingsMap(). As of this writing there are 58 pure virtual methods that start with "Get" in Profile.

Profile should be a minimal reference, a sort of handle object that doesn't own the world.


Design Goals

  • We must be able to move to the new architecture piece-wise. One service and feature at a time. We can not stop the world and convert everything in one operation. As of this writing, we've moved 19 services out of Profile.
    • We should only make small modifications at the callsite where a Profile is used to get the service in question.
  • We must fix Profile shutdown. When we started and only had a few objects hanging off of Profile, manual ordering was acceptable for destruction. Now we have over seventy five components and we know that our manual destruction ordering is incorrect as written today. We can not rely on manual ordering when we have so many components.
  • We must allow features to be compiled in and out. Now that we have chromium variants that don't contain all the features in a standard Windows/Mac/Linux Google Chrome build, we need a way to allow these variants to compile without #ifdefing profile.h and profile_impl.h into a mess. These variants also have their own services that they'd like to provide. (Letting chromium variants add their own services also touches on why we can't rely on manual ordering in Profile shutdown.)
    • Stretch goal: Separate features go in their own .a/.so files to further minimize our ridiculous linking time.

ProfileKeyedServiceFactory

The Old Way: Profile interface and ProfileImpl

In the previous design, services were fetched through an accessor on Profile:

class ProfileImpl {
  public:
    virtual FooService* GetFooService();
  private:
    scoped_ptr<FooService> foo_service_;
};

In the previous system, Profile was an interface with mostly pure virtual accessors. There were separate versions of Profile for Normal, Incognito and Testing profiles.

In this world, the Profile was the center of all activity. The profile owned all of its service and handed them out. Profile destruction was according to whatever order the services were listed in ProfileImpl. There wasn't a way for another variant to add its own services (or leave out ones it didn't need) without modifying the Profile interface.

The New Way: ProfileKeyedServiceFactory

Instead of having the Profile own FooService, we have a dedicated singleton FooServiceFactory, like this minimal one:

class FooServiceFactory : public ProfileKeyedServiceFactory {
 public:
  static FooService* GetForProfile(Profile* profile);

  static FooServiceFactory* GetInstance();

 private:
  friend struct DefaultSingletonTraits<FooServiceFactory>;

  FooServiceFactory();
  virtual ~FooServiceFactory();

  // ProfileKeyedServiceFactory:
  virtual ProfileKeyedService* BuildServiceInstanceFor(
    Profile* profile) const OVERRIDE;
};

We have a generalized ProfileKeyedServiceFactory which performs most of the work of associating a profile with an object provided by your BuildServiceInstanceFor() method. The ProfileKeyedServiceFactory provides an interface for you to override while managing the lifetime of your Service object in response to Profile lifetime events and making sure your service is shut down before services it depends on.

An absolutely minimal factory will supply the following methods:
  • A static GetInstance() method that refers to your Factory as a Singleton.
  • A constructor that associates this ProfileKeyedServiceFactory with the ProfileDependencyManager singleton, and makes DependsOn() declarations.
  • A GetForProfile() method that wrapsProfileKeyedServiceFactory, casting the result back to whatever type you need to return.
  • A BuildServiceInstanceFor() method which is called once by the framework for each |profile|, which must return a proper instance of your service.
In addition, ProfileKeyedServiceFactory provides these other knobs for how you can control behavior:
  • RegisterUserPrefs() is called once per Profile during initialization and is where you can place any user pref registration.
  • By default, PKSF return NULL when given an Incognito profile.
    • If you override ServiceRedirectedInIncognito() to return true, it will return the associated normal Profile's service.
    • If you override ServiceHasOwnInstanceInIncognito() to return true, it will create a new service for the incognito profile.
  • By default, PKSF will lazily create your service. If you override ServiceIsCreatedWithProfile() to return true, your service will be created alongside the profile.
  • PKSF gives you multiple ways to control behavior during unit tests. See the header for more details.
  • PKSF gives you a way to augment and tweak the shutdown and deallocation behavior.

A Brief Interlude About Complexity

So the above, from an implementation standpoint is significantly more complex than what came before it. Is all this really worth it?

Yes.

We absolutely have to address the interdependency of services. As it stands today, we do not shut down profiles after they are no longer needed in multiprofile mode because our crash rate when shutting down a profile is too high to ship to users. We have about 75 components that plug into the profile lifecycle and their dependency graph is complex enough that our naive manual ordering can not handle the complexity. All of the overrideable behavior above exists because it was implemented per service, ad hoc and copy pasted.

We likewise need to make it easy for other chromium variants to add their own features/compile features out of their build.

Dependency Management Overview

With that in mind, let's look at how dependency management works. There is a single ProfileDependencyManager singleton, which is what is alerted to Profile creation and destruction. A PKSF will register and unregister itself with the ProfileDependencyManager . The job of the ProfileDependencyManager is to make sure that individual services are created and destroyed in a safe ordering.

Consider the case of these three service factories:

AlphaServiceFactory::AlphaServiceFactory()
    : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) {
}

BetaServiceFactory::BetaServiceFactory()
    :
 ProfileKeyedServiceFactory( ProfileDependencyManager::GetInstance())  {
  DependsOn(AlphaServiceFactory::GetInstance());
     }

GammaServiceFactory::GammaServiceFactory()
    :
 ProfileKeyedServiceFactory( ProfileDependencyManager::GetInstance())  {
  DependsOn(BetaServiceFactory::GetInstance());
     }

The explicitly stated dependencies in this simplified graph mean that the only valid creation order for services is [Alpha, Beta, Gamma] and the destruction order is [Gamma, Beta, Alpha]. The above is all you, as a user of the framework, have to do to specify dependencies.

Behind the scenes, ProfileDependencyManager takes the stated dependency edges, performs a Kahn topological sort, and uses that in CreateProfileServices() and DestroyProfileServices() .

The Five Minute Tutorial of How to Convert Your Code

  1. Make Your Existing FooService derive from ProfileKeyedService.
  2. If possible, make your FooService no longer refcounted. Most of the refcounted objects that hang off of Profile appear to be that way because they aren't using base::bind/WeakPtrFactory instead of needing to own data on multiple threads.
  3. Build a simple FooServiceFactory derived from ProfileKeyedServiceFactory. Your FooServiceFactory will be the main access point consumers will ask for FooService. ProfileKeyedServiceFactory gives you a bunch of virtual methods that control behavior.
    1. ProfileKeyedService* ProfileKeyedServiceFactory::BuildServiceInstanceFor(Profile* profile) is the only required method. Given a Profile handle, return a valid FooService.
    2. You can control the incognito behavior with ServiceRedirectedInIncognito() and ServiceHasOwnInstanceInIncognito().
  4. Add your service to the AssertFactoriesBuilt() list in profile_dependency_manager.cc.
  5. Understand shutdown behavior. For historical reasons, we have a two phase deletion process:
    1. Every ProfileKeyedService will first have its Shutdown() method called. Use this method to drop weak references to the Profile or other service objects.
    2. Every ProfileKeyedService is deleted and its destructor is run. Minimal work should be done here. Attempts to call any *ServiceFactory::GetForProfile() will cause an assertion in debug mode.
  6. Change each instance of "profile_->GetFooService()" to "FooServiceFactory::GetForProfile(profile_)".
If you need an example of what the above looks like, try looking at these patches:
  • r100516: A simple example, adding a new ProfileKeyedService. This shows off a minimal ServiceFactory subclass.
  • r104806: plugin_prefs_factory.h gives an example of how to deal with things that are (and have to stay) refcounted. This patch also shows off how to move your preferences into your ProfileKeyedServiceFactory.

Debugging Tips

Using the dependency visualizer

Chrome has a built in method to dump the profile dependency graph to a file inGraphViz format. When you run chrome with the command line flag   --dump-profile-graph , chrome will write the dependency information to your /path/to/profile/profile-dependencies.dot file. You can then convert this text file with dot, which is part of GraphViz:

dot -Tpng /path/to/profile/profile-dependencies.dot > png-file.png

This will give you a visual graph like this (generated January 23rd, 2012, click through for full size):


Crashses at Shutdown

If you get a stack that looks like this:

ProfileDependencyManager::AssertProfileWasntDestroyed()
ProfileKeyedServiceFactory::GetServiceForProfile()
MyServiceFactory::GetForProfile()
... [Probably a bunch of frames] ...
OtherService::~OtherService()
ProfileKeyedServiceFactory::ProfileDestroyed()
ProfileDependencyManager::DestroyProfileServices()
ProfileImpl::~ProfileImpl()

The problem is that OtherSerivce is improperly depending on MyService. The framework asserts if you try to use a Shutdown()ed component.
内容概要:该论文研究增程式电动汽车(REEV)的能量管理策略,针对现有优化策略实时性差的问题,提出基于工况识别的自适应等效燃油消耗最小策略(A-ECMS)。首先建立整车Simulink模型和基于规则的策略;然后研究动态规划(DP)算法和等效燃油最小策略;接着通过聚类分析将道路工况分为四类,并设计工况识别算法;最后开发基于工况识别的A-ECMS,通过高德地图预判工况类型并自适应调整SOC分配。仿真显示该策略比规则策略节油8%,比简单SOC规划策略节油2%,并通过硬件在环实验验证了实时可行性。 适合人群:具备一定编程基础,特别是对电动汽车能量管理策略有兴趣的研发人员和技术爱好者。 使用场景及目标:①理解增程式电动汽车能量管理策略的基本原理;②掌握动态规划算法和等效燃油消耗最小策略的应用;③学习工况识别算法的设计和实现;④了解基于工况识别的A-ECMS策略的具体实现及其优化效果。 其他说明:此资源不仅提供了详细的MATLAB/Simulink代码实现,还深入分析了各算法的原理和应用场景,适合用于学术研究和工业实践。在学习过程中,建议结合代码调试和实际数据进行实践,以便更好地理解策略的优化效果。此外,论文还探讨了未来的研究方向,如深度学习替代聚类、多目标优化以及V2X集成等,为后续研究提供了思路。
内容概要:论文《基于KANN-DBSCAN带宽优化的核密度估计载荷谱外推》针对传统核密度估计(KDE)载荷外推中使用全局固定带宽的局限性,提出了一种基于改进的K平均最近邻DBSCAN(KANN-DBSCAN)聚类算法优化带宽选择的核密度估计方法。该方法通过对载荷数据进行KANN-DBSCAN聚类分组,采用拇指法(ROT)计算各簇最优带宽,再进行核密度估计和蒙特卡洛模拟外推。实验以电动汽车实测载荷数据为对象,通过统计参数、拟合度和伪损伤三个指标验证了该方法的有效性,误差显著降低,拟合度R²>0.99,伪损伤接近1。 适合人群:具备一定编程基础和载荷数据分析经验的研究人员、工程师,尤其是从事汽车工程、机械工程等领域的工作1-5年研发人员。 使用场景及目标:①用于电动汽车载荷谱编制,提高载荷预测的准确性;②应用于机械零部件的载荷外推,特别是非对称载荷分布和多峰扭矩载荷;③实现智能网联汽车载荷预测与数字孪生集成,提供动态更新的载荷预测系统。 其他说明:该方法不仅解决了传统KDE方法在复杂工况下的“过平滑”与“欠拟合”问题,还通过自适应参数机制提高了方法的普适性和计算效率。实际应用中,建议结合MATLAB代码实现,确保数据质量,优化参数并通过伪损伤误差等指标进行验证。此外,该方法可扩展至风电装备、航空结构健康监测等多个领域,未来研究方向包括高维载荷扩展、实时外推和多物理场耦合等。
有的时候是突发性的,日志也没有预兆root@norco:/data# top top - 16:51:14 up 1:11, 1 user, load average: 4.53, 4.40, 4.36 Tasks: 212 total, 5 running, 207 sleeping, 0 stopped, 0 zombie %Cpu(s): 98.5 us, 1.4 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st MiB Mem : 1967.8 total, 1659.5 free, 99.5 used, 208.8 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 1842.8 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2622 root 20 0 148 4 0 R 99.0 0.0 68:11.67 burnCor+ 2625 root 20 0 148 4 0 R 99.0 0.0 68:07.12 burnCor+ 2623 root 20 0 148 4 0 R 98.0 0.0 68:08.58 burnCor+ 2624 root 20 0 148 4 0 R 96.7 0.0 67:57.51 burnCor+ 23 root -2 0 0 0 0 S 2.3 0.0 1:03.48 ktimers+ 398 root 20 0 283920 1448 1284 S 1.3 0.1 0:40.63 rknn_se+ 2626 root 20 0 16040 3348 2672 R 1.3 0.2 0:42.84 top 10 root -2 0 0 0 0 S 1.0 0.0 0:43.28 ktimers+ 31 root -2 0 0 0 0 S 0.7 0.0 0:40.68 ktimers+ 39 root -2 0 0 0 0 S 0.7 0.0 0:42.06 ktimers+ 1 root 20 0 168536 9952 6988 S 0.0 0.5 0:05.60 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.01 kthreadd 3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp 4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par+ 6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker+ 8 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_perc+ 9 root 20 0 0 0 0 S 0.0 0.0 0:00.58 ksoftir+ DDR 03ea844c5d typ 24/09/03-10:42:57,fwver: v1.23 In 136.081379] Buffer I/O error on dev sda1, logical block 32769, lost async page write wdqs_if: 0x1010100 LP4/4x derate en, other dram:2x trefi ddrconfig:0 MID:0xff LPDDR4X, 324MHz BW=32 Col=10 Bk=8 CS0 Row=16 CS=1 Die BW=16 Size=2048MB tdqss_lf: cs0 dqs0: 24ps, dqs1: -72ps, dqs2: -24ps, dqs3: -144ps, tdqss_hf: cs0 dqs0: 24ps, dqs1: -72ps, dqs2: -24ps, dqs3: -144ps, change to: 324MHz PHY drv:clk:36,ca:36,DQ:29,odt:240 vrefinner:16%, vrefout:41% dram drv:40,odt:0 clk skew:0x62 change to: 528MHz PHY drv:clk:36,ca:36,DQ:29,odt:240 vrefinner:16%, vrefout:41% dram drv:40,odt:0 clk skew:0x58 change to: 780MHz PHY drv:clk:36,ca:36,DQ:29,odt:60 vrefinner:16%, vrefout:41% dram drv:40,odt:0 clk skew:0x58 rx vref: 15.6% tx vref: 36.0% change to: 1560MHz(final freq) PHY drv:clk:36,ca:36,DQ:29,odt:60 vrefinner:16%, vrefout:22% dram drv:40,odt:80 vref_ca:00000071 clk skew:0x30 rx vref: 14.6% tx vref: 22.8% cs 0: rdtrn RS: DQS0:0x34, DQS1:0x34, DQS2:0x36, DQS3:0x2e, min :0x10 0x12 0x14 0x12 0x2 0x6 0xb 0x7 , 0xc 0xa 0x1 0x6 0xe 0xc 0xc 0xa , 0x12 0x11 0xd 0xc 0x4 0x2 0x4 0x7 , 0xa 0x7 0x5 0x2 0xd 0x10 0x9 0x10 , mid :0x2b 0x2c 0x2e 0x2b 0x1d 0x21 0x25 0x22 ,0x27 0x25 0x1c 0x20 0x29 0x25 0x26 0x25 , 0x2c 0x2d 0x27 0x26 0x1e 0x1d 0x1d 0x21 ,0x25 0x22 0x1f 0x1b 0x28 0x2a 0x25 0x2a , max :0x46 0x47 0x49 0x44 0x39 0x3d 0x40 0x3d ,0x43 0x41 0x38 0x3a 0x44 0x3f 0x41 0x40 , 0x46 0x49 0x41 0x41 0x39 0x38 0x37 0x3b ,0x41 0x3d 0x3a 0x35 0x43 0x44 0x41 0x45 , range:0x36 0x35 0x35 0x32 0x37 0x37 0x35 0x36 ,0x37 0x37 0x37 0x34 0x36 0x33 0x35 0x36 , 0x34 0x38 0x34 0x35 0x35 0x36 0x33 0x34 ,0x37 0x36 0x35 0x33 0x36 0x34 0x38 0x35 , wrtrn RS: DQS0:0x34, DQS1:0x22, DQS2:0x2c, DQS3:0x14, min :0x6f 0x74 0x75 0x73 0x63 0x66 0x6b 0x68 0x69 ,0x5a 0x58 0x52 0x53 0x5e 0x5a 0x5c 0x5a 0x57 , 0x69 0x6a 0x63 0x63 0x5c 0x58 0x5a 0x5e 0x5e ,0x52 0x4f 0x4c 0x48 0x53 0x54 0x4e 0x57 0x4c , mid :0x8a 0x8e 0x90 0x8e 0x7d 0x80 0x84 0x81 0x82 ,0x74 0x72 0x6b 0x6c 0x77 0x74 0x75 0x73 0x71 , 0x85 0x85 0x7e 0x7e 0x75 0x71 0x74 0x78 0x78 ,0x6c 0x69 0x66 0x62 0x6e 0x6e 0x6a 0x71 0x67 , max :0xa6 0xa9 0xab 0xa9 0x97 0x9b 0x9e 0x9b 0x9b ,0x8f 0x8d 0x84 0x85 0x91 0x8e 0x8e 0x8d 0x8c , 0xa1 0xa1 0x99 0x99 0x8f 0x8b 0x8e 0x93 0x93 ,0x86 0x84 0x81 0x7c 0x8a 0x89 0x86 0x8c 0x83 , range:0x37 0x35 0x36 0x36 0x34 0x35 0x33 0x33 0x32 ,0x35 0x35 0x32 0x32 0x33 0x34 0x32 0x33 0x35 , 0x38 0x37 0x36 0x36 0x33 0x33 0x34 0x35 0x35 ,0x34 0x35 0x35 0x34 0x37 0x35 0x38 0x35 0x37 , CBT RS: cs:0 min :0x48 0x49 0x3e 0x39 0x3d 0x36 0x42 ,0x47 0x40 0x3e 0x36 0x39 0x35 0x41 , cs:0 mid :0x87 0x88 0x7a 0x78 0x7a 0x75 0x6f ,0x85 0x80 0x79 0x75 0x76 0x75 0x6d , cs:0 max :0xc6 0xc8 0xb7 0xb7 0xb7 0xb5 0x9d ,0xc4 0xc1 0xb5 0xb5 0xb3 0xb5 0x9a , cs:0 range:0x7e 0x7f 0x79 0x7e 0x7a 0x7f 0x5b ,0x7d 0x81 0x77 0x7f 0x7a 0x80 0x59 , out U-Boot SPL board init U-Boot SPL 2017.09-g606f72bd97a-240527 #lxh (May 30 2024 - 16:08:15), fwver: v1.14 unknown raw ID 0 0 0 unrecognized JEDEC id bytes: 00, 00, 00 Trying to boot from MMC2 MMC: no card present mmc_init: -123, time 2 spl: mmc init failed with error: -123 Trying to boot from MMC1 SPL: A/B-slot: _a, successful: 0, tries-remain: 7 Trying fit image at 0x4000 sector ## Verified-boot: 0 ## Checking atf-1 0x00040000 ... sha256(7a570b5b74...) + OK ## Checking uboot 0x00a00000 ... sha256(a66b064c48...) + OK ## Checking fdt 0x00b43160 ... sha256(036cca5880...) + OK ## Checking atf-2 0xfdcc1000 ... sha256(fdb854226f...) + OK ## Checking atf-3 0x0006b000 ... sha256(cd11fffcf0...) + OK ## Checking atf-4 0xfdcce000 ... sha256(353be80a4d...) + OK ## Checking atf-5 0xfdcd0000 ... sha256(8fb6de1f19...) + OK ## Checking atf-6 0x00069000 ... sha256(a87216a14d...) + OK ## Checking optee 0x08400000 ... sha256(ac96eda7b3...) + OK Jumping to U-Boot(0x00a00000) via ARM Trusted Firmware(0x00040000) Total: 200.422/478.232 ms INFO: Preloader serial: 2 NOTICE: BL31: v2.3():v2.3-662-g30c17915b-dirty:cl, fwver: v1.02 NOTICE: BL31: Built : 16:39:01, Nov 2 2023 INFO: GICv3 without legacy support detected. INFO: ARM GICv3 driver initialized in EL3 INFO: pmu v1 is valid 220114 INFO: cache_write_streaming_cfg:0 2808bc00 PCTL:L3-7 L1-5 WSCTL:L1-0 L3-1 INFO: cache_write_streaming_cfg:0 2808e400 PCTL:L3-1 L1-7 WSCTL:L1-0 L3-1 INFO: l3 cache partition cfg-8421 INFO: dfs DDR fsp_param[0].freq_mhz= 1560MHz INFO: dfs DDR fsp_param[1].freq_mhz= 324MHz INFO: dfs DDR fsp_param[2].freq_mhz= 528MHz INFO: dfs DDR fsp_param[3].freq_mhz= 780MHz INFO: Using opteed sec cpu_context! INFO: boot cpu mask: 0 INFO: BL31: Initializing runtime services INFO: BL31: Initializing BL32 I/TC: I/TC: OP-TEE version: 3.13.0-860-g6c78a7d8c #hisping.lin (gcc version 10.2.1 20201103 (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16))) #2 Mon Sep 2 09:47:08 CST 2024 aarch64, fwver: v2.14 I/TC: OP-TEE memory: TEEOS 0x200000 TA 0xc00000 SHM 0x200000 I/TC: Primary CPU initializing I/TC: CRYPTO_CRYPTO_VERSION_NEW no support. Skip all algo mode check. I/TC: Primary CPU switching to normal world boot INFO: BL31: Preparing for EL3 exit to normal world INFO: Entry point address = 0xa00000 INFO: SPSR = 0x3c9 U-Boot 2017.09-gd43e71c0a7-230727 #xuke (Jun 10 2025 - 09:51:12 +0800) Model: Rockchip RK3568 Evaluation Board MPIDR: 0x81000000 PreSerial: 2, raw, 0xfe660000 DRAM: 2 GiB Sysmem: init Relocation Offset: 7d21c000 Relocation fdt: 7b9f8e40 - 7b9fece0 CR: M/C/I Using default environment 类似这种,我在跑满载,突然重启
08-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值