Skip to content

Commit

Permalink
Bug 802367 - The main event: Let a browser process inherit its app's …
Browse files Browse the repository at this point in the history
…id. r=bz,cjones

The main bug fixed here is that in half of our interfaces, we use "is browser frame/element" to mean "browser or app", and in the other half, we use it to mean "is browser not app".

There's a related, functional bug also fixed here, which is that a browser process doesn't inherit its parent's app-id.  This causes problems e.g. for IndexedDB: If a browser inside an app uses IndexedDB, the DB should have the app's app-id.

I also modified Tab{Parent,Child} and nsFrameLoader to call "app" "ownOrContainingApp", to emphasize that we might have inherited the app from a parent process.  I left nsIDocShell::appId alone, because changing that would have necessitated changing nsILoadGroup and therefore a /lot/ of users in Necko; it's also not clear it would have clarified anything in those cases.
  • Loading branch information
jlebar committed Oct 30, 2012
1 parent 0fa468e commit e831cd6
Show file tree
Hide file tree
Showing 25 changed files with 436 additions and 374 deletions.
2 changes: 1 addition & 1 deletion content/base/src/nsDocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8359,7 +8359,7 @@ HasCrossProcessParent(nsIDocument* aDocument)
if (!docShell) {
return false;
}
return docShell->GetIsContentBoundary();
return docShell->GetIsBrowserOrApp();
}

static bool
Expand Down
159 changes: 98 additions & 61 deletions content/base/src/nsFrameLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ nsFrameLoader::ShowRemoteFrame(const nsIntSize& size)
EnsureMessageManager();

nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (OwnerIsBrowserFrame() && os && !mRemoteBrowserInitialized) {
if (OwnerIsBrowserOrAppFrame() && os && !mRemoteBrowserInitialized) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
"remote-browser-frame-shown", NULL);
mRemoteBrowserInitialized = true;
Expand Down Expand Up @@ -1393,25 +1393,23 @@ nsFrameLoader::SetOwnerContent(Element* aContent)
}

bool
nsFrameLoader::OwnerIsBrowserFrame()
nsFrameLoader::OwnerIsBrowserOrAppFrame()
{
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
bool isBrowser = false;
if (browserFrame) {
browserFrame->GetReallyIsBrowser(&isBrowser);
}
return isBrowser;
return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
}

bool
nsFrameLoader::OwnerIsAppFrame()
{
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
bool isApp = false;
if (browserFrame) {
browserFrame->GetReallyIsApp(&isApp);
}
return isApp;
return browserFrame ? browserFrame->GetReallyIsApp() : false;
}

bool
nsFrameLoader::OwnerIsBrowserFrame()
{
return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame();
}

void
Expand All @@ -1424,6 +1422,55 @@ nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut)
}
}

already_AddRefed<mozIApplication>
nsFrameLoader::GetOwnApp()
{
nsAutoString manifest;
GetOwnerAppManifestURL(manifest);
if (manifest.IsEmpty()) {
return nullptr;
}

nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(appsService, nullptr);

nsCOMPtr<mozIDOMApplication> domApp;
appsService->GetAppByManifestURL(manifest, getter_AddRefs(domApp));

nsCOMPtr<mozIApplication> app = do_QueryInterface(domApp);
MOZ_ASSERT_IF(domApp, app);
return app.forget();
}

already_AddRefed<mozIApplication>
nsFrameLoader::GetOwnOrContainingApp()
{
nsCOMPtr<mozIApplication> app = GetOwnApp();
if (app) {
return app.forget();
}

// See if our owner content's principal has an associated app.
uint32_t appId = mOwnerContent->NodePrincipal()->GetAppId();
MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);

if (appId == nsIScriptSecurityManager::NO_APP_ID ||
appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
return nullptr;
}

nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(appsService, nullptr);

nsCOMPtr<mozIDOMApplication> domApp;
appsService->GetAppByLocalId(appId, getter_AddRefs(domApp));
MOZ_ASSERT(domApp);

app = do_QueryInterface(domApp);
MOZ_ASSERT_IF(domApp, app);
return app.forget();
}

bool
nsFrameLoader::ShouldUseRemoteProcess()
{
Expand All @@ -1440,15 +1487,15 @@ nsFrameLoader::ShouldUseRemoteProcess()

// If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
// fall back to the default.
if (OwnerIsBrowserFrame() &&
if (OwnerIsBrowserOrAppFrame() &&
!mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) {

return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
}

// Otherwise, we're remote if we have "remote=true" and we're either a
// browser frame or a XUL element.
return (OwnerIsBrowserFrame() ||
return (OwnerIsBrowserOrAppFrame() ||
mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
mOwnerContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::Remote,
Expand Down Expand Up @@ -1495,24 +1542,6 @@ nsFrameLoader::MaybeCreateDocShell()
mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);

if (OwnerIsBrowserFrame()) {
nsAutoString manifest;
GetOwnerAppManifestURL(manifest);
if (!manifest.IsEmpty()) {
nsCOMPtr<nsIAppsService> appsService =
do_GetService(APPS_SERVICE_CONTRACTID);
if (!appsService) {
NS_ERROR("Apps Service is not available!");
return NS_ERROR_FAILURE;
}

uint32_t appId;
appsService->GetAppLocalIdByManifestURL(manifest, &appId);

mDocShell->SetAppId(appId);
}
}

if (!mNetworkCreated) {
nsCOMPtr<nsIDocShellHistory> history = do_QueryInterface(mDocShell);
if (history) {
Expand Down Expand Up @@ -1614,9 +1643,34 @@ nsFrameLoader::MaybeCreateDocShell()

EnsureMessageManager();

if (OwnerIsAppFrame()) {
// You can't be both an app and a browser frame.
MOZ_ASSERT(!OwnerIsBrowserFrame());

nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
MOZ_ASSERT(ownApp);
uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
if (ownApp) {
NS_ENSURE_SUCCESS(ownApp->GetLocalId(&ownAppId), NS_ERROR_FAILURE);
}

mDocShell->SetIsApp(ownAppId);
}

if (OwnerIsBrowserFrame()) {
mDocShell->SetIsBrowserElement();
// You can't be both a browser and an app frame.
MOZ_ASSERT(!OwnerIsAppFrame());

nsCOMPtr<mozIApplication> containingApp = GetOwnOrContainingApp();
uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
if (containingApp) {
NS_ENSURE_SUCCESS(containingApp->GetLocalId(&containingAppId),
NS_ERROR_FAILURE);
}
mDocShell->SetIsBrowserInsideApp(containingAppId);
}

if (OwnerIsBrowserOrAppFrame()) {
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
Expand Down Expand Up @@ -1948,7 +2002,7 @@ nsFrameLoader::TryRemoteBrowser()
nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));

// <iframe mozbrowser> gets to skip these checks.
if (!OwnerIsBrowserFrame()) {
if (!OwnerIsBrowserOrAppFrame()) {
int32_t parentType;
parentAsItem->GetItemType(&parentType);

Expand Down Expand Up @@ -1984,35 +2038,18 @@ nsFrameLoader::TryRemoteBrowser()
return false;
}

bool isBrowserElement = false;
// Get our own or containing app only if we're a browser or app frame. We
// want to avoid the situation where, if we're a remote frame that's neither
// a browser nor an app frame, we pass our containing app to
// ContentParent::CreateBrowserOrApp below, because that would effectively
// give this non-browser-or-app frame app privileges.
nsCOMPtr<mozIApplication> app;
if (OwnerIsBrowserFrame()) {
isBrowserElement = true;

nsAutoString manifest;
GetOwnerAppManifestURL(manifest);
if (!manifest.IsEmpty()) {
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (!appsService) {
NS_ERROR("Apps Service is not available!");
return false;
}

nsCOMPtr<mozIDOMApplication> domApp;
appsService->GetAppByManifestURL(manifest, getter_AddRefs(domApp));
// If the frame is actually an app, we should not mark it as a
// browser. This is to identify the data store: since <app>s
// and <browser>s-within-<app>s have different stores, we want
// to ensure the <app> uses its store, not the one for its
// <browser>s.
app = do_QueryInterface(domApp);
if (app) {
isBrowserElement = false;
}
}
if (OwnerIsBrowserOrAppFrame()) {
app = GetOwnOrContainingApp();
}

if ((mRemoteBrowser = ContentParent::CreateBrowser(app, isBrowserElement))) {
mRemoteBrowser = ContentParent::CreateBrowserOrApp(app, OwnerIsBrowserFrame());
if (mRemoteBrowser) {
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
mRemoteBrowser->SetOwnerElement(element);

Expand Down Expand Up @@ -2322,7 +2359,7 @@ nsFrameLoader::EnsureMessageManager()
return rv;
}

if (!mIsTopLevelContent && !OwnerIsBrowserFrame() && !mRemoteFrame) {
if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) {
return NS_OK;
}

Expand Down
24 changes: 22 additions & 2 deletions content/base/src/nsFrameLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class nsITabParent;
class nsIDocShellTreeItem;
class nsIDocShellTreeOwner;
class nsIDocShellTreeNode;
class mozIApplication;

namespace mozilla {
namespace dom {
Expand Down Expand Up @@ -313,22 +314,41 @@ class nsFrameLoader MOZ_FINAL : public nsIFrameLoader,
/**
* Is this a frameloader for a bona fide <iframe mozbrowser> or
* <iframe mozapp>? (I.e., does the frame return true for
* nsIMozBrowserFrame::GetReallyIsBrowser()?)
* nsIMozBrowserFrame::GetReallyIsBrowserOrApp()?)
*/
bool OwnerIsBrowserFrame();
bool OwnerIsBrowserOrAppFrame();

/**
* Is this a frameloader for a bona fide <iframe mozapp>? (I.e., does the
* frame return true for nsIMozBrowserFrame::GetReallyIsApp()?)
*/
bool OwnerIsAppFrame();

/**
* Is this a frame loader for a bona fide <iframe mozbrowser>?
*/
bool OwnerIsBrowserFrame();

/**
* Get our owning element's app manifest URL, or return the empty string if
* our owning element doesn't have an app manifest URL.
*/
void GetOwnerAppManifestURL(nsAString& aOut);

/**
* Get the app for our frame. This is the app whose manifest is returned by
* GetOwnerAppManifestURL.
*/
already_AddRefed<mozIApplication> GetOwnApp();

/**
* Get the closest app to our frame. This is either the frame returned by
* GetOwnApp() or the app associated with our owner element's principal.
*
* That is, this method returns the app that our owner content is inside.
*/
already_AddRefed<mozIApplication> GetOwnOrContainingApp();

/**
* If we are an IPC frame, set mRemoteFrame. Otherwise, create and
* initialize mDocShell.
Expand Down
13 changes: 7 additions & 6 deletions content/base/src/nsInProcessTabChildGlobal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,15 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
mDelayedDisconnect(false), mOwner(aOwner), mChromeMessageManager(aChrome)
{

// If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our
// PreHandleEvent implementation.
// If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
// have to tweak our PreHandleEvent implementation.
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
bool isBrowser = false;
if (browserFrame) {
browserFrame->GetReallyIsBrowser(&isBrowser);
mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
}
else {
mIsBrowserOrAppFrame = false;
}
mIsBrowserFrame = isBrowser;
}

nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
Expand Down Expand Up @@ -268,7 +269,7 @@ nsInProcessTabChildGlobal::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;

if (mIsBrowserFrame &&
if (mIsBrowserOrAppFrame &&
(!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
if (mOwner) {
nsPIDOMWindow* innerWindow = mOwner->OwnerDoc()->GetInnerWindow();
Expand Down
7 changes: 4 additions & 3 deletions content/base/src/nsInProcessTabChildGlobal.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,10 @@ class nsInProcessTabChildGlobal : public nsDOMEventTargetHelper,
bool mLoadingScript;
bool mDelayedDisconnect;

// Is this the message manager for an in-process <iframe mozbrowser>? This
// affects where events get sent, so it affects PreHandleEvent.
bool mIsBrowserFrame;
// Is this the message manager for an in-process <iframe mozbrowser> or
// <iframe mozapp>? This affects where events get sent, so it affects
// PreHandleEvent.
bool mIsBrowserOrAppFrame;
public:
nsIContent* mOwner;
nsFrameMessageManager* mChromeMessageManager;
Expand Down
10 changes: 3 additions & 7 deletions content/events/src/nsEventStateManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1570,14 +1570,10 @@ nsEventStateManager::IsRemoteTarget(nsIContent* target) {
return true;
}

// <frame/iframe mozbrowser>
// <frame/iframe mozbrowser/mozapp>
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(target);
if (browserFrame) {
bool isBrowser = false;
browserFrame->GetReallyIsBrowser(&isBrowser);
if (isBrowser) {
return !!TabParent::GetFrom(target);
}
if (browserFrame && browserFrame->GetReallyIsBrowserOrApp()) {
return !!TabParent::GetFrom(target);
}

return false;
Expand Down
Loading

0 comments on commit e831cd6

Please sign in to comment.