Profile Architecture
This page details an ongoing design refactoring, started in January 2012.
Profile should be a minimal reference, a sort of handle object that doesn't own the world.
Design Goals
ProfileKeyedServiceFactoryThe Old Way: Profile interface and ProfileImpl
In the previous design, services were fetched through an accessor on Profile:
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 {
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:
In addition, ProfileKeyedServiceFactory provides these other knobs for how you can control 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.
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()} GammaServiceFactory::GammaServiceFactory()}
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()
.
If you need an example of what the above looks like, try looking at these patches:
Debugging TipsUsing 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:
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() The problem is that OtherSerivce is improperly depending on MyService. The framework asserts if you try to use a Shutdown()ed component. |