Commit 6bc04fd8 authored by aa@chromium.org's avatar aa@chromium.org

Add site_instance_id to ProcessMap::Item.

This is needed because there can be two site instances for the
same extension/process pair. Boo.

The linear scan for Contains() is a bummer. I thought about
more exotic data structures, but it didn't seem worth it.

BUG=105328

Review URL: http://codereview.chromium.org/8769022

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112921 0039d316-1c4b-4281-b951-d872f2087c98
parent 953620b6
...@@ -457,14 +457,16 @@ void ChromeContentBrowserClient::SiteInstanceGotProcess( ...@@ -457,14 +457,16 @@ void ChromeContentBrowserClient::SiteInstanceGotProcess(
if (!extension) if (!extension)
return; return;
service->process_map()->Insert( service->process_map()->Insert(extension->id(),
extension->id(), site_instance->GetProcess()->GetID()); site_instance->GetProcess()->GetID(),
site_instance->id());
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, BrowserThread::IO, FROM_HERE,
base::Bind(&ExtensionInfoMap::RegisterExtensionProcess, base::Bind(&ExtensionInfoMap::RegisterExtensionProcess,
profile->GetExtensionInfoMap(), profile->GetExtensionInfoMap(),
extension->id(), extension->id(),
site_instance->GetProcess()->GetID())); site_instance->GetProcess()->GetID(),
site_instance->id()));
} }
void ChromeContentBrowserClient::SiteInstanceDeleting( void ChromeContentBrowserClient::SiteInstanceDeleting(
...@@ -485,14 +487,16 @@ void ChromeContentBrowserClient::SiteInstanceDeleting( ...@@ -485,14 +487,16 @@ void ChromeContentBrowserClient::SiteInstanceDeleting(
if (!extension) if (!extension)
return; return;
service->process_map()->Remove( service->process_map()->Remove(extension->id(),
extension->id(), site_instance->GetProcess()->GetID()); site_instance->GetProcess()->GetID(),
site_instance->id());
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, BrowserThread::IO, FROM_HERE,
base::Bind(&ExtensionInfoMap::UnregisterExtensionProcess, base::Bind(&ExtensionInfoMap::UnregisterExtensionProcess,
profile->GetExtensionInfoMap(), profile->GetExtensionInfoMap(),
extension->id(), extension->id(),
site_instance->GetProcess()->GetID())); site_instance->GetProcess()->GetID(),
site_instance->id()));
} }
bool ChromeContentBrowserClient::ShouldSwapProcessesForNavigation( bool ChromeContentBrowserClient::ShouldSwapProcessesForNavigation(
......
...@@ -107,8 +107,9 @@ bool ExtensionInfoMap::CanCrossIncognito(const Extension* extension) { ...@@ -107,8 +107,9 @@ bool ExtensionInfoMap::CanCrossIncognito(const Extension* extension) {
} }
void ExtensionInfoMap::RegisterExtensionProcess(const std::string& extension_id, void ExtensionInfoMap::RegisterExtensionProcess(const std::string& extension_id,
int process_id) { int process_id,
if (!process_map_.Insert(extension_id, process_id)) { int site_instance_id) {
if (!process_map_.Insert(extension_id, process_id, site_instance_id)) {
NOTREACHED() << "Duplicate extension process registration for: " NOTREACHED() << "Duplicate extension process registration for: "
<< extension_id << "," << process_id << "."; << extension_id << "," << process_id << ".";
} }
...@@ -116,15 +117,16 @@ void ExtensionInfoMap::RegisterExtensionProcess(const std::string& extension_id, ...@@ -116,15 +117,16 @@ void ExtensionInfoMap::RegisterExtensionProcess(const std::string& extension_id,
void ExtensionInfoMap::UnregisterExtensionProcess( void ExtensionInfoMap::UnregisterExtensionProcess(
const std::string& extension_id, const std::string& extension_id,
int process_id) { int process_id,
if (!process_map_.Remove(extension_id, process_id)) { int site_instance_id) {
if (!process_map_.Remove(extension_id, process_id, site_instance_id)) {
NOTREACHED() << "Unknown extension process registration for: " NOTREACHED() << "Unknown extension process registration for: "
<< extension_id << "," << process_id << "."; << extension_id << "," << process_id << ".";
} }
} }
void ExtensionInfoMap::UnregisterAllExtensionsInProcess(int process_id) { void ExtensionInfoMap::UnregisterAllExtensionsInProcess(int process_id) {
process_map_.Remove(process_id); process_map_.RemoveAllFromProcess(process_id);
} }
bool ExtensionInfoMap::SecurityOriginHasAPIPermission( bool ExtensionInfoMap::SecurityOriginHasAPIPermission(
......
...@@ -55,11 +55,13 @@ class ExtensionInfoMap : public base::RefCountedThreadSafe<ExtensionInfoMap> { ...@@ -55,11 +55,13 @@ class ExtensionInfoMap : public base::RefCountedThreadSafe<ExtensionInfoMap> {
// Adds an entry to process_map_. // Adds an entry to process_map_.
void RegisterExtensionProcess(const std::string& extension_id, void RegisterExtensionProcess(const std::string& extension_id,
int process_id); int process_id,
int site_instance_id);
// Removes an entry from process_map_. // Removes an entry from process_map_.
void UnregisterExtensionProcess(const std::string& extension_id, void UnregisterExtensionProcess(const std::string& extension_id,
int process_id); int process_id,
int site_instance_id);
void UnregisterAllExtensionsInProcess(int process_id); void UnregisterAllExtensionsInProcess(int process_id);
// Returns true if there is exists an extension with the same origin as // Returns true if there is exists an extension with the same origin as
......
...@@ -2373,7 +2373,7 @@ void ExtensionService::Observe(int type, ...@@ -2373,7 +2373,7 @@ void ExtensionService::Observe(int type,
installed_app_hosts_.erase(process->GetID()); installed_app_hosts_.erase(process->GetID());
process_map_.Remove(process->GetID()); process_map_.RemoveAllFromProcess(process->GetID());
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, BrowserThread::IO, FROM_HERE,
base::Bind(&ExtensionInfoMap::UnregisterAllExtensionsInProcess, base::Bind(&ExtensionInfoMap::UnregisterAllExtensionsInProcess,
......
...@@ -7,21 +7,27 @@ ...@@ -7,21 +7,27 @@
namespace extensions { namespace extensions {
// Item // Item
ProcessMap::Item::Item() { struct ProcessMap::Item {
} Item() {
}
ProcessMap::Item::Item(const ProcessMap::Item& other) explicit Item(const ProcessMap::Item& other)
: extension_id(other.extension_id), process_id(other.process_id) { : extension_id(other.extension_id),
} process_id(other.process_id),
site_instance_id(other.site_instance_id) {
}
ProcessMap::Item::Item(const std::string& extension_id, int process_id) Item(const std::string& extension_id, int process_id,
: extension_id(extension_id), process_id(process_id) { int site_instance_id)
} : extension_id(extension_id),
process_id(process_id),
site_instance_id(site_instance_id) {
}
ProcessMap::Item::~Item() { ~Item() {
} }
bool ProcessMap::Item::operator<(const ProcessMap::Item& other) const { bool operator<(const ProcessMap::Item& other) const {
if (extension_id < other.extension_id) if (extension_id < other.extension_id)
return true; return true;
...@@ -30,8 +36,19 @@ bool ProcessMap::Item::operator<(const ProcessMap::Item& other) const { ...@@ -30,8 +36,19 @@ bool ProcessMap::Item::operator<(const ProcessMap::Item& other) const {
return true; return true;
} }
if (extension_id == other.extension_id &&
process_id == other.process_id &&
site_instance_id < other.site_instance_id) {
return true;
}
return false; return false;
} }
std::string extension_id;
int process_id;
int site_instance_id;
};
// ProcessMap // ProcessMap
...@@ -41,15 +58,17 @@ ProcessMap::ProcessMap() { ...@@ -41,15 +58,17 @@ ProcessMap::ProcessMap() {
ProcessMap::~ProcessMap() { ProcessMap::~ProcessMap() {
} }
bool ProcessMap::Insert(const std::string& extension_id, int process_id) { bool ProcessMap::Insert(const std::string& extension_id, int process_id,
return items_.insert(Item(extension_id, process_id)).second; int site_instance_id) {
return items_.insert(Item(extension_id, process_id, site_instance_id)).second;
} }
bool ProcessMap::Remove(const std::string& extension_id, int process_id) { bool ProcessMap::Remove(const std::string& extension_id, int process_id,
return items_.erase(Item(extension_id, process_id)) > 0; int site_instance_id) {
return items_.erase(Item(extension_id, process_id, site_instance_id)) > 0;
} }
int ProcessMap::Remove(int process_id) { int ProcessMap::RemoveAllFromProcess(int process_id) {
int result = 0; int result = 0;
for (ItemSet::const_iterator iter = items_.begin(); iter != items_.end(); ) { for (ItemSet::const_iterator iter = items_.begin(); iter != items_.end(); ) {
if (iter->process_id == process_id) { if (iter->process_id == process_id) {
...@@ -64,7 +83,12 @@ int ProcessMap::Remove(int process_id) { ...@@ -64,7 +83,12 @@ int ProcessMap::Remove(int process_id) {
bool ProcessMap::Contains(const std::string& extension_id, bool ProcessMap::Contains(const std::string& extension_id,
int process_id) const { int process_id) const {
return items_.find(Item(extension_id, process_id)) != items_.end(); for (ItemSet::const_iterator iter = items_.begin(); iter != items_.end();
++iter) {
if (iter->process_id == process_id && iter->extension_id == extension_id)
return true;
}
return false;
} }
bool ProcessMap::Contains(int process_id) const { bool ProcessMap::Contains(int process_id) const {
......
...@@ -16,6 +16,7 @@ namespace extensions { ...@@ -16,6 +16,7 @@ namespace extensions {
// Contains information about which extensions are assigned to which processes. // Contains information about which extensions are assigned to which processes.
// //
// The relationship between extensions and processes is complex: // The relationship between extensions and processes is complex:
//
// - Extensions can be either "split" mode or "spanning" mode. // - Extensions can be either "split" mode or "spanning" mode.
// - In spanning mode, extensions share a single process between all incognito // - In spanning mode, extensions share a single process between all incognito
// and normal windows. This was the original mode for extensions. // and normal windows. This was the original mode for extensions.
...@@ -23,6 +24,8 @@ namespace extensions { ...@@ -23,6 +24,8 @@ namespace extensions {
// - There are also hosted apps, which are a kind of extensions, and those // - There are also hosted apps, which are a kind of extensions, and those
// usually have a process model similar to normal web sites: multiple // usually have a process model similar to normal web sites: multiple
// processes per-profile. // processes per-profile.
// - A single hosted app can have more than one SiteInstance in the same process
// if we're over the process limit and force them to share a process.
// //
// In general, we seem to play with the process model of extensions a lot, so // In general, we seem to play with the process model of extensions a lot, so
// it is safest to assume it is many-to-many in most places in the codebase. // it is safest to assume it is many-to-many in most places in the codebase.
...@@ -43,12 +46,14 @@ namespace extensions { ...@@ -43,12 +46,14 @@ namespace extensions {
// it is an "extension process" (e.g., for UI purposes). It may contain only // it is an "extension process" (e.g., for UI purposes). It may contain only
// hosted apps. See crbug.com/102533. // hosted apps. See crbug.com/102533.
// //
// 2. An extension can show be in multiple processes. That is why there is no // 2. An extension can show up in multiple processes. That is why there is no
// GetExtensionProcess() method here. There are two cases: a) The extension // GetExtensionProcess() method here. There are two cases: a) The extension
// is actually a hosted app, in which case this is normal, or b) there is an // is actually a hosted app, in which case this is normal, or b) there is an
// incognito window open and the extension is "split mode". It is *not safe* // incognito window open and the extension is "split mode". It is *not safe*
// to assume that there is one process per extension. If you only care about // to assume that there is one process per extension. If you only care about
// extensions (not hosted apps), and you are on the UI thread, then use // extensions (not hosted apps), and you are on the UI thread, and you don't
// care about incognito version of this extension (or vice versa if you're in
// an incognito profile) then use
// ExtensionProcessManager::GetSiteInstanceForURL()->[Has|Get]Process(). // ExtensionProcessManager::GetSiteInstanceForURL()->[Has|Get]Process().
// //
// 3. The process ids contained in this class are *not limited* to the Profile // 3. The process ids contained in this class are *not limited* to the Profile
...@@ -64,30 +69,23 @@ class ProcessMap { ...@@ -64,30 +69,23 @@ class ProcessMap {
size_t size() const { return items_.size(); } size_t size() const { return items_.size(); }
bool Insert(const std::string& extension_id, int process_id); bool Insert(const std::string& extension_id, int process_id,
bool Remove(const std::string& extension_id, int process_id); int site_instance_id);
int Remove(int process_id);
bool Remove(const std::string& extension_id, int process_id,
int site_instance_id);
int RemoveAllFromProcess(int process_id);
bool Contains(const std::string& extension_id, int process_id) const; bool Contains(const std::string& extension_id, int process_id) const;
bool Contains(int process_id) const; bool Contains(int process_id) const;
std::set<std::string> GetExtensionsInProcess(int process_id) const; std::set<std::string> GetExtensionsInProcess(int process_id) const;
private: private:
struct Item { struct Item;
Item();
Item(const Item& other);
Item(const std::string& extension_id, int process_id);
~Item();
// Required for set membership.
bool operator<(const Item& other) const;
std::string extension_id;
int process_id;
};
typedef std::set<Item> ItemSet; typedef std::set<Item> ItemSet;
std::set<Item> items_; ItemSet items_;
DISALLOW_COPY_AND_ASSIGN(ProcessMap); DISALLOW_COPY_AND_ASSIGN(ProcessMap);
}; };
......
...@@ -13,25 +13,25 @@ TEST(ExtensionProcessMapTest, Test) { ...@@ -13,25 +13,25 @@ TEST(ExtensionProcessMapTest, Test) {
// Test behavior when empty. // Test behavior when empty.
EXPECT_FALSE(map.Contains("a", 1)); EXPECT_FALSE(map.Contains("a", 1));
EXPECT_FALSE(map.Remove("a", 1)); EXPECT_FALSE(map.Remove("a", 1, 1));
EXPECT_EQ(0u, map.size()); EXPECT_EQ(0u, map.size());
// Test insertion and behavior with one item. // Test insertion and behavior with one item.
EXPECT_TRUE(map.Insert("a", 1)); EXPECT_TRUE(map.Insert("a", 1, 1));
EXPECT_TRUE(map.Contains("a", 1)); EXPECT_TRUE(map.Contains("a", 1));
EXPECT_FALSE(map.Contains("a", 2)); EXPECT_FALSE(map.Contains("a", 2));
EXPECT_FALSE(map.Contains("b", 1)); EXPECT_FALSE(map.Contains("b", 1));
EXPECT_EQ(1u, map.size()); EXPECT_EQ(1u, map.size());
// Test inserting a duplicate item. // Test inserting a duplicate item.
EXPECT_FALSE(map.Insert("a", 1)); EXPECT_FALSE(map.Insert("a", 1, 1));
EXPECT_TRUE(map.Contains("a", 1)); EXPECT_TRUE(map.Contains("a", 1));
EXPECT_EQ(1u, map.size()); EXPECT_EQ(1u, map.size());
// Insert some more items. // Insert some more items.
EXPECT_TRUE(map.Insert("a", 2)); EXPECT_TRUE(map.Insert("a", 2, 2));
EXPECT_TRUE(map.Insert("b", 1)); EXPECT_TRUE(map.Insert("b", 1, 3));
EXPECT_TRUE(map.Insert("b", 2)); EXPECT_TRUE(map.Insert("b", 2, 4));
EXPECT_EQ(4u, map.size()); EXPECT_EQ(4u, map.size());
EXPECT_TRUE(map.Contains("a", 1)); EXPECT_TRUE(map.Contains("a", 1));
...@@ -40,13 +40,26 @@ TEST(ExtensionProcessMapTest, Test) { ...@@ -40,13 +40,26 @@ TEST(ExtensionProcessMapTest, Test) {
EXPECT_TRUE(map.Contains("b", 2)); EXPECT_TRUE(map.Contains("b", 2));
EXPECT_FALSE(map.Contains("a", 3)); EXPECT_FALSE(map.Contains("a", 3));
// Note that this only differs from an existing item because of the site
// instance id.
EXPECT_TRUE(map.Insert("a", 1, 5));
EXPECT_TRUE(map.Contains("a", 1));
// Test removal. // Test removal.
EXPECT_TRUE(map.Remove("a", 1)); EXPECT_TRUE(map.Remove("a", 1, 1));
EXPECT_FALSE(map.Remove("a", 1)); EXPECT_FALSE(map.Remove("a", 1, 1));
EXPECT_EQ(4u, map.size());
// Should still return true because there were two site instances for this
// extension/process pair.
EXPECT_TRUE(map.Contains("a", 1));
EXPECT_TRUE(map.Remove("a", 1, 5));
EXPECT_EQ(3u, map.size()); EXPECT_EQ(3u, map.size());
EXPECT_FALSE(map.Contains("a", 1));
EXPECT_EQ(2, map.Remove(2)); EXPECT_EQ(2, map.RemoveAllFromProcess(2));
EXPECT_EQ(1u, map.size()); EXPECT_EQ(1u, map.size());
EXPECT_EQ(0, map.Remove(2)); EXPECT_EQ(0, map.RemoveAllFromProcess(2));
EXPECT_EQ(1u, map.size()); EXPECT_EQ(1u, map.size());
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment