 Thanks to Sam. I've gotten really good at drawing the diagrams on these slides because I had to draw them over and over and over again and turn them into a presentation. Also, it was good to see the Mojo talk. I worked with Ken in the early days of Chrome adopting Mojo. He used my feature as a guinea pig for a lot of how Mojo works. It's completely different now. So now I'm like, oh, is that a date? It's very annoying. OK, so in the talk that John gave earlier today, he introduced a lot of the overall principles about how we organize Chrome, multiprocess architecture, services, that kind of thing. What I'd like to do here is take some of that content and dive a little deeper and really give you a tour through the classes that make up the Chrome application so that when you're trying to find some of these things, like, what is a render frame host, you actually know what that is. You can map that to a concept in the UI and it'll hopefully help you think through how Chrome works a little more easily. So one of the really big divides in the Chromium project is that it is both the Chrome browser, Google Chrome browser, and also a library that other applications can use to build their own browser. And you see that with things like Android WebView or the Electron project. They are other embedders of what we call the content layer. So there's this separation between, I don't know if you can actually see the laser pointer, content and Chrome. And so Chrome is said to embed content. And so for a lot of the objects I'm going to be talking about here, there are both Chrome versions and content versions where the Chrome version sort of adds more of the Chrome browser product features on top of the core content, just rendering layer. OK, so Chrome, it's an application like any other application, it has a main function somewhere. When you double click the icon, it starts running code somewhere in that giant binary. And that is inside the browser process. So no matter how many windows or tabs you have open, there's always a single browser process and that's the parent of everything else, renderers, GPU processes, utility processes. There are a couple of major objects that live in the browser process. The first one is browser process. One of these gets created when the browser starts and it exists for the whole life of the browser. The content layer provides the sort of core browser main loop object and has an extension mechanism that allows embedders to add other pieces. And that's the browser main parts which Chrome extends to create Chrome browser main parts. And the reason that I mentioned these is that one of the things that makes testing easier is avoiding globals, making sure that you actually, like every object really has a well-defined lifetime. And so you may be tempted if you want to have some piece of state that you say, oh, that lives for as long as the process. Well, if you're in a test, you might want to tear it down and start it up over and over again. So maybe instead of making it a global, attach it to one of these top level browser process or Chrome browser main parts classes so that it effectively lives forever. But during a test, you can actually start it up and shut it down and make sure that that works as well. So looking at like some pieces of the Chrome UI, one feature that Chrome has is that it allows users to create separate profiles. And these can be used to separate personal and work browsing histories or if you share your computer with your family, you may have different people using the computer at different times. And we created profiles to allow users to be able to share a single computer without getting their data all mixed up. So you don't want to have to log your sister out of Gmail just to check your mail. You can just open your profile and leave everything that she was working on alone. Profiles work a little differently on different platforms. So this dialogue you see here is what it looks like on desktop platforms like Windows or Mac OS where you can have multiple profiles active at the same time and each of them just has their own collection of Windows. On Chrome OS, your profile is what you get when you log in. So everything you see when you log into Chrome OS is your profile, but it actually does have a secret profile switcher function, which until they get rid of it, which apparently they're planning on it, it's going to, it supports sort of a multi desktop mode. Another feature of profiles in Chrome is the idea of incognito. So incognito is designed to allow the user to choose to turn off history for a little while. You know, it doesn't save cookies, it doesn't save browser history. And the way that it does this is it creates a special off the record profile object. And the off the record profile has all the same storage APIs that a normal profile does. It provides the same kind of hooks for setting cookies or adding history, but it doesn't actually write any of that to disk. And so when you close the window and the off the record profile is deleted, all that data is gone and it's like it never happened. One of the quirks though about how incognito works is that it actually still retains a reference back to the original profile. And the reason for this is that when you're in incognito mode, you still want to have your bookmarks, you still want to have it auto fill passwords if you want to be able to log into a site. And so there's always a reference from the off the record profile back to the real profile. And some features can use that in order to continue to assist the user even if they are in incognito. But of course you have to be careful because you don't want to leak user data into the incognito window unless you are really sure the user wants you to like for a safe password. Similar to incognito is guest mode. So guest mode is designed for a slightly different use case where incognito is for sort of turning off history for a second. Guest mode is for if you want to lend your computer to somebody else. And you usually see this most on Chrome OS but it does work on desktop as well. Guest mode reuses most of the infrastructure from incognito mode but instead of creating the incognito profile based on your current profile it basically creates an empty sort of blank throwaway profile and then initializes all the incognito functionality on top of it. So it still doesn't save anything to disk but it also doesn't retain any of the state from before you went into guest mode. And so it's kind of a fresh clean slate whenever you start it up. Okay, so going back to some other pieces of the UI this I'm sure you're familiar with is what Chrome looks like. But sort of now that we've talked about some of the main objects we can sort of we can actually point out some things in what they correspond to. So for example, we were talking about profiles and up here in the corner we have the profile icon which indicates which profile that window belongs to. Now, so each window, so we talked about the browser process object that is global to the entire browser process. Each window confusingly is referenced is represented by a browser object. So when you see a browser object in the code that doesn't refer to the entire Chrome browser process that just refers to that particular window. We should probably rename it browser window at some point. I don't want to start that bike shit. So inside a window you also have tabs and there's a class called tab strip model that manages that list of tabs that are associated with a particular window. And then we wouldn't be a web browser without web content and so web content is what gets drawn in the middle of the window and that's really what we're gonna be talking about for the rest of the talk. Okay, so before we do that, let's just sort of talk about a couple more concepts that we often find in the code base. Some of them there can be kind of confusing. So many features will have per profile data and it'd be a real mess if every feature had to add their own fields to browser context or the profile objects. And this is especially necessary if we want to provide isolation between Chrome and content because remember that we provide both this big application that's Chrome and we also provide this library that other people can use to build their own sort of browser applications. And so we have a couple of patterns that are useful for attaching data to existing classes and one of the classes that most often gets data attached to it is the browser context or the profile. And there are two main patterns for how to do that. The most common is called base supports user data. And the idea is that if you have some data you wanna attach another object like browser context, you have it implement supports user data data and you can attach it to the browser context by just calling set user data and giving it a key. And then if you later have a browser context and wanna see if you've added some data to it before it's called get user data. And this makes the lifetime of your data really easy to reason about because when the browser context gets destroyed your data gets destroyed. You can check if the data was there, very easy to manage. Slightly more complicated is the keyed service. Keyed services work essentially the same you attach an object to an existing browser context. But they support kind of a two phase shutdown where before the object gets destroyed we first do a pass to say, okay we wanna shut down all these services. And that's useful for things like browser context because there's so many interdependencies between things associated with a profile that it's useful to be able to sort of shut down all those relationships first and then destroy the objects. But because of that additional complexity there's this class called browser context keyed service factory, I know it's a mouthful which manages the dependencies and the shut ends sort of setting up and tearing down all those objects. So if you see those around that's what they are. They're a very useful pattern. I remember telling Sam that he needed to use a browser context keyed service and getting a blank look. Okay, so like I said, browser it's all about web content. So probably one of the most important objects in all of Chrome is web contents. So web contents represents the data that is it represents a tab. We could call it tab but we called it web contents. Web contents demonstrates that the reason we don't call it tab is because while all tabs have a web contents that is what is drawn in that content area there are a bunch of things that aren't tabs that are web contents. So for example, you can have web contents that are in standalone application windows. You can have web contents that show up in like pop-up dialogues from extensions and stuff like that. So while you can assume that every tab is web contents not every web contents is a tab. So web contents demonstrates a number of patterns that you'll see all over the Chrome code base. The first of which is that user data pattern. So in addition to attaching things to browser contexts people often attach things to web contents. And so there are a lot of web contents user data. In Chrome you'll often see these referred to as a tab helper. And the idea is that if you have a feature that needs to store some state related to a tab you create a web contents user data for that. And it's basically an object that helps out when you're implementing that feature holding onto the data related to a tab. So you'll see lots of tab helpers for various features like extensions, tab helper and stuff like that. Another pattern that you'll see demonstrated with web contents is the observer pattern. So there are lots of interesting events that can happen to a web contents. So it could navigate, it could crash. And so there's an observer interface that you can implement in order to get all those events from the web contents. Since tab helpers often want to know when the tab they're helping with has done something interesting a very often a web contents user data is also a web contents observer. The last pattern is the delegate or the client. So web contents is a class inside of the content layer. So web contents just knows how to draw content. It doesn't want to have any complicated details about how exactly the browser works. And so it has to call out into Chrome to do things like display a file picker if you want to upload an attachment to your email. Content knows how to upload a file and knows how to do all the networking stuff related to that. But it doesn't know how the browser wants to ask the user about the file. So content requires that the embedder, in this case Chrome, implement the web contents delegate interface and implement the run file chooser method which will return whatever file the user picked. And so that's one of the places where we have the interface between content and Chrome as an embedder. There are a whole bunch of other ones. Oh, the front, okay. So on this side, we have a whole bunch of other classes that are part of the content public interface. And on this side, we have all of the classes that are Chrome's implementation of those interfaces. And so you'll see this term client use. The idea is that content has a client as the thing that's embedding it. And the client has to implement a bunch of functions in order to provide the functionality that the content depends on. And Chrome is not the only embedder of content in the source tree. So if you look at a class like content client, you'll also see an Android WebView content client. You'll see a headless content client for other applications that use content within them. Okay, so you learned earlier that Chrome is using a multiprocess model to separate parsing and rendering execution of untrusted content from the main browser process. In order to display that content, the browser creates a frame into which the render process can draw content. So now that we've gotten into this multiprocess architecture and we've got all these layers, we serve how we have a whole bunch of objects to bear with me for a second. So content has a content to actually embeds Blink, which is our HTML rendering engine. And so when we create a frame in which to draw a web content, first we have a local frame. Blink exposes its interface to things like content by usually prefixing the class name with web. So there's a web local frame, which is part of the Blink public interface. Content owns that in a render frame, which is part of the content public interface. And this all exists inside the render process. This arrow, which I've sort of glossed over is all the Mojo stuff that Ken and Oksana just talked about. And so the browser has this render frame host object that is the sort of companion to the render frame between the browser and render processes. In IPC, you'll often see, when you have objects on either side of an IPC boundary, in Chrome, you'll often see this host suffix on the owning process side. So there'll be a render frame host in the browser, which represents a render frame. There'll be a render process host. There'll be a GPU process host. That sort of comes out of the semantics of the old IPC system. In components using Mojo, you'll often see service instead of host, though naming does tend to vary and everybody can call things what they want. Okay, so to dive a little bit deeper into a more complex example, Chrome originally started using multiple render processes in order to isolate stability problems triggered by one tab from the other tab. So if Gmail starts using too much memory, that tab crashes, all your other tabs are fine. With the launch of Site Isolation, which I know that the security talks are gonna go into in more detail tomorrow, we've also used the multiprocess model in order to provide a really good security boundary in order to keep code owned by different origins in separate processes. And a different part of that transition, which again will be talked about tomorrow is the introduction of out-of-process iframes. Which might lead you to wonder, okay, what is an iframe? So when the browser is rendering a site, so in this example, we have gone to a.com and we've loaded that document. Well, that document contained a couple tags. It contained an iframesource a.com tag and an iframesource b.com tag. And what the iframe tag tells the browser to do is create a new content area inside the existing content area and load another document within that. And because we have this multiprocess model and we have site isolation, what we actually are doing behind the scenes, in the UI, you see one sort of consistent rendered experience of all of these origins together. In the background, we've actually created multiple render processes. One render process is handling everything related to a.com. And so we have two frames, both the main content frame and one of the iframes being rendered by that process. And then in the other process, we have the rendering happening for the other frame. And what you get with this document and all these iframes is a tree, which is called the frame tree, where every tab has one main frame, but then you could have sort of arbitrarily nested more additional frames with additional origins. And one of the big pieces of what content does as a library is manage all these render processes and figure out how to render all these documents and how to combine them all together into a single and sort of a single experience. Another thing, I really need to file a bug about slides and font rendering. So let's find on my machine. So another detail, I was just going to do the last little detail about profiles. So when I was talking about profiles, we're talking about things like user history, cookies, storage, these are actually split into sort of two categories. All of the user's preferences, so things about their browsing history, their bookmarks, their saved passwords, those are associated with a profile. However, information about, the information that a website stores, so things like cookies, local storage, index DB, those are actually stored in something called a storage partition. A storage partition is a concept within content. And the idea of a storage partition, and for the most part, data in a storage partition all ends up in the default. So for a given profile, you have a default storage partition where all the data is stored. But there are a couple of features where we actually want to be able to create sort of isolated browsing contexts. One of the places where this happens is inside of Chrome apps. So Chrome app can create a web view which allows the user to sort of get, visualize the application to build its own web browser, essentially similar to what Android WebView does for Android applications. Chrome apps have a web view tag which can do the same thing. And so since the Chrome app is running under the context of a particular user, that data would go into that user's profile. But since the application is kind of creating its own browser, that web view gets its own storage partition where all of the cookies and storage from sites loaded in that web view are stored. And that is my last slide. So I want to thank the folks who helped me put together this presentation, a video who sat through a much rougher run-through of this for me yesterday. John, who is responsible for so much of Chrome's architecture and also helped me review this presentation. So I just want to thank them and thank you all for listening and coming today. So I think we have about 10 minutes for questions. Seven. Okay, seven minutes. He wants to let you out early. All right, so any questions? No questions. I was wondering about the definition of a mainframe. Is there one mainframe per web contents or is there one mainframe per site? There's one mainframe per web contents. The mainframe is really just kind of the root of the frame tree. With like site isolation, if you have all these like xyz.github.io and then something else to github.io, they're actually like different sites even though they have the same. So I think they're going to go into much more detail on exactly how that works in the security talk tomorrow. There's a belief that the way that site isolation works is that it segments things by sort of the effective top level domain. So github.com is a single site from that perspective. But there are some details over there that I am not absolutely familiar with. So I think there'll be a lot more detail on that tomorrow. There's a question back there. So regarding the render frame host tree, so how long can it be? Is there any limit where we can restrict it? I don't believe there's a limit. I think you can create new render frames until you run out of memory. Either that or it's something unreasonable like 64. So I'm not new to Chrome. I've been on Chrome for a long time but this is a debate that never seems to end which is, and I would like to ask you to explain in as gruesome a detail as you can the meaning of delegate versus client versus proxy. And in particular, why would we call us, like why do we use the name web contents delegate rather than just file picker or date picker? In other words, adding delegate there makes it sound like this is something that is inherently a part of the web contents idea and it's not. The idea is that it's a file picker or a date picker which is implemented by the browser. Do you understand? Yeah, so I think I understand. So yeah, so I think the first answer is that the English language has lots of words that mean similar things and nobody can decide which word is the best one. But I think that there is a little, in the delegate versus client naming, for example, the idea in web contents delegate is that web contents as an object, web contents impulse really is delegating to this other class some details of how it's implemented. That's from my justification for the use of the word delegate. Now it's possible that if it specifically was the method to create a file picker, for example, you could have a web contents delegate method called get file picker and it'd be completely reasonable for that to return like a stood unique pointer file picker that provides the rest of that interface and you wouldn't have to call that file picker delegate. Like you could just call it file picker. I think that client is used in a lot of the other cases because the Chrome would be considered a client of the content API and so that's the interface that the clients have to implement. But like I said, most of the those specifications that I came up with while writing this talk and trying to see if I could like come up with a really good reason why that was what these things were called. I think that it's just, you know, certain, it's like they're between host and like host doesn't make sense anymore, but it used to we call things services now. Maybe services would make sense. Maybe we'll rename them in a few years. Naming is hard. Isn't that one of the major problems of computer science naming things? So a question regarding the frame host and then the frames where you briefly touched this before. So I just wanted to clarify. By the figure you had on the screen, it seems like frame host kind of owns the render, the render frame via, you know, across the processes, right? So does it like actually owning it or does it have a pointer to them or not even, it's not even like that kind of ownership. I just want to come. Yes, so I've glossed over a little bit of details in like the exact ownership relationship between render frame and web local frame and local frame. They're effectively what each of those owns the other, but people more familiar with those exact interfaces will probably tell me I'm wrong. There's actually some life cycle involved there. But actually specifically about the render frame host to render frame ownership model because I think that one is the most interesting. There are a number of ways in which you can do ownership across a mojo pipe. So there often is this concept you'll see of the idea of a pipe owning an object. And the idea there is that, you know, the render frame host might be connected to the render frame and if the render frame goes away and the render frame host can be destroyed as well because those two objects sort of have a shared fate. And because you're across two processes, you don't have just, it's not as simple as just, you know, C++ constructors and destructors, but there is still this idea of this kind of shared fate between two objects across an IPC channel where if one is destroyed, the other one won't be destroyed immediately because there's some messages that have to go across the channel to tell the other side that something has gone away. But yes, they essentially have the same lifetime and they would both be destroyed at roughly the same time. Be careful about that roughly the same time thing though because there have been a number of crash bugs related to the fact that people assume that render frame host has been destroyed as soon as the render frame is destroyed and it's not quite, it's almost. So the question was why is this called a local frame? The reason for that is that out-of-process IFrame concept. So because in this example, we have, so we have one frame here that's the main frame and we have one frame here which ends up being in the same process. So over in this render process, this frame has a reference to this frame as a local frame but this frame has a reference to this frame as a remote frame because that's in a different process. And it was a big sort of refactoring effort to actually support the concept of supporting all the APIs related to frames in that frame tree relationship when some of the frames weren't actually in the same process. So to tag on to my original question, for render process, the low render process there, which one is the main frame there? In the lower render process, there is no main frame in that render process. So that render process only exists. The main frame is a concept of a tab. So it's one of the things that happens when you go from the browser process to the render process, the render process knows about the frame tree but it doesn't care as much as the browser process does because it's just drawing into boxes and it's up to the compositor like where it puts it and it's up to the browser process to decide like what priority it is. So what would you get if you asked, like if you call get main frame on the render frame down there, what'd you get? If you, so there is no get main frame method in the render process. The method you get in the render process is, there is a method on frame that's get parent and in get parent, you would be able to get a remote reference to the parent frame from the other frame but the concept of a web contents, the concept of a tab that has a main frame is a browser process concept. Do we have a web API for the contents of the one of the subframes to know that they're not the main frame? Yes, so there's some details there that have to do with cross origin iframes and whether cross origin iframes, how much data about each other across origin iframes get. Let's just assume that all the frames were same origin. You can ask yourself as a document who your parent is and so an iframe can actually walk all the way up the tree to it's most parent, most parent. It's just that if you go across the cross origin boundary you get less information about that because we allow same origin iframes to actually access each other's variables and do all sorts of stuff. Whereas cross origin iframes just kind of forget to know that each other exists and that's about it. You mentioned that user data is attached to the browser context and the web content or? Profile, so profile inherits from browser context. So browser context is what content calls a profile and profile is what Chrome calls a profile. You give an example of some of that user data. Yes, so in the example is example here. So your browser history, your bookmarks, sort of like the user application information, like user preferences, all of that is in the profile. And then as a subset of that you have the data stored on behalf of individual applications and that's what goes into storage partitions. First question there. Where does the cache fit in this picture? I think it's in the storage partitions. So the storage partitions also includes all of the network context. And so that, yeah, that's for storage partition. The cache is actually owned by the network, the network service process, but the connection, the each storage partition gets its own connection to the network service that maintains sort of a separate context for each one. So you mentioned a couple of questions ago that when you cross like an origin boundary you get less information about the other neighboring iframes, is that like a security feature to prevent like the cross site request forgery? Yeah, so yeah, the idea is that you shouldn't be able to, like if you embed some iframe in your page that iframe shouldn't be able to go and read all of the information, all like, you know, it shouldn't be able to read all of the content of the page that it's embedded in. Unless the page is embedded and wants it to and then there are ways you can pass information so you can opt in to passing information into an iframe but by default they're segregated. Where is the secret Chrome OS feature for multiple profiles and why are we getting rid of it? So if you've logged into Chrome OS, if you have multiple user accounts in Chrome OS and you've logged into one and you go into the system menu and then click on your profile icon it will give you an option below that that's like sign in additional profile. I think that that's turning into something that'll look more like the way that desktop uses it where you just sign in and then you have multiple profiles with multiple windows. So it'll sort of unify how it works between Chrome OS and other platforms. So I was curious about when you sort of crossed the render process boundary, like if you traverse the get parent and you said you get less information how is that actually, how is that built? You get like some sort of proxy object because I would assume that if you get parent you would expect the render frame object to return. Would you get something else instead? Yeah, so this is why out of process iframes were hard and I would ask this question tomorrow in security talk when they start talking about it's talking about site isolation out of process iframes. Because yes, a lot of the APIs really were built with the assumption that you could get information about all the frames associated with a single like parent main document in the same process and separating that out into multiple processes made it substantially more complicated.