Bug 802366 - The main event: Let a browser process inherit its app's 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.
This commit is contained in:
Justin Lebar 2012-11-09 16:37:39 -08:00
parent 1063cbe1b5
commit 785d3c9b2f
29 changed files with 1028 additions and 472 deletions

View File

@ -8359,7 +8359,7 @@ HasCrossProcessParent(nsIDocument* aDocument)
if (!docShell) {
return false;
}
return docShell->GetIsContentBoundary();
return docShell->GetIsBrowserOrApp();
}
static bool

View File

@ -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;
@ -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
@ -1424,6 +1422,50 @@ 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::GetContainingApp()
{
// 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);
nsCOMPtr<mozIApplication> app = do_QueryInterface(domApp);
MOZ_ASSERT_IF(domApp, app);
return app.forget();
}
bool
nsFrameLoader::ShouldUseRemoteProcess()
{
@ -1440,7 +1482,7 @@ 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);
@ -1448,7 +1490,7 @@ nsFrameLoader::ShouldUseRemoteProcess()
// 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,
@ -1495,24 +1537,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) {
@ -1614,9 +1638,34 @@ nsFrameLoader::MaybeCreateDocShell()
EnsureMessageManager();
if (OwnerIsBrowserFrame()) {
mDocShell->SetIsBrowserElement();
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()) {
// You can't be both a browser and an app frame.
MOZ_ASSERT(!OwnerIsAppFrame());
nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
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),
@ -1948,7 +1997,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);
@ -1984,35 +2033,18 @@ nsFrameLoader::TryRemoteBrowser()
return false;
}
bool isBrowserElement = false;
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;
}
}
MutableTabContext context;
nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
if (ownApp) {
context.SetTabContextForAppFrame(ownApp, containingApp);
} else if (OwnerIsBrowserFrame()) {
// The |else| above is unnecessary; OwnerIsBrowserFrame() implies !ownApp.
context.SetTabContextForBrowserFrame(containingApp);
}
if ((mRemoteBrowser = ContentParent::CreateBrowser(app, isBrowserElement))) {
mRemoteBrowser = ContentParent::CreateBrowserOrApp(context);
if (mRemoteBrowser) {
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
mRemoteBrowser->SetOwnerElement(element);
@ -2322,7 +2354,7 @@ nsFrameLoader::EnsureMessageManager()
return rv;
}
if (!mIsTopLevelContent && !OwnerIsBrowserFrame() && !mRemoteFrame) {
if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) {
return NS_OK;
}

View File

@ -33,6 +33,7 @@ class nsITabParent;
class nsIDocShellTreeItem;
class nsIDocShellTreeOwner;
class nsIDocShellTreeNode;
class mozIApplication;
namespace mozilla {
namespace dom {
@ -313,9 +314,9 @@ private:
/**
* 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
@ -323,12 +324,29 @@ private:
*/
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 app which contains this frame. This is the app associated with
* the frame element's principal.
*/
already_AddRefed<mozIApplication> GetContainingApp();
/**
* If we are an IPC frame, set mRemoteFrame. Otherwise, create and
* initialize mDocShell.

View File

@ -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()
@ -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();

View File

@ -122,9 +122,10 @@ protected:
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;

View File

@ -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;

View File

@ -278,8 +278,8 @@ nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
* needs to have the right attributes, and its creator must have the right
* permissions.)
*/
nsresult
nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
/* [infallible] */ nsresult
nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp(bool *aOut)
{
*aOut = false;
@ -289,9 +289,9 @@ nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
}
// Fail if this frame doesn't have the mozbrowser attribute.
bool isBrowser = false;
GetMozbrowser(&isBrowser);
if (!isBrowser) {
bool hasMozbrowser = false;
GetMozbrowser(&hasMozbrowser);
if (!hasMozbrowser) {
return NS_OK;
}
@ -299,7 +299,7 @@ nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
nsIPrincipal *principal = NodePrincipal();
nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
NS_ENSURE_STATE(permMgr);
NS_ENSURE_TRUE(permMgr, NS_OK);
uint32_t permission = nsIPermissionManager::DENY_ACTION;
nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission);
@ -308,7 +308,7 @@ nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
return NS_OK;
}
NS_IMETHODIMP
/* [infallible] */ NS_IMETHODIMP
nsGenericHTMLFrameElement::GetReallyIsApp(bool *aOut)
{
nsAutoString manifestURL;
@ -324,9 +324,7 @@ nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
aOut.Truncate();
// At the moment, you can't be an app without being a browser.
bool isBrowser = false;
GetReallyIsBrowser(&isBrowser);
if (!isBrowser) {
if (!nsIMozBrowserFrame::GetReallyIsBrowserOrApp()) {
return NS_OK;
}
@ -334,7 +332,7 @@ nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
nsIPrincipal *principal = NodePrincipal();
nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
NS_ENSURE_STATE(permMgr);
NS_ENSURE_TRUE(permMgr, NS_OK);
uint32_t permission = nsIPermissionManager::DENY_ACTION;
nsresult rv = permMgr->TestPermissionFromPrincipal(principal,
@ -352,11 +350,10 @@ nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
}
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
NS_ENSURE_STATE(appsService);
NS_ENSURE_TRUE(appsService, NS_OK);
nsCOMPtr<mozIDOMApplication> app;
appsService->GetAppByManifestURL(manifestURL, getter_AddRefs(app));
if (app) {
aOut.Assign(manifestURL);
}

View File

@ -326,7 +326,7 @@ bool nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIRequest *request,
parentDocShellItem) {
nsCOMPtr<nsIDocShell> curDocShell = do_QueryInterface(curDocShellItem);
if (curDocShell && curDocShell->GetIsContentBoundary()) {
if (curDocShell && curDocShell->GetIsBrowserOrApp()) {
break;
}

View File

@ -730,6 +730,7 @@ nsDocShell::nsDocShell():
mCharsetReloadState(eCharsetReloadInit),
mChildOffset(0),
mBusyFlags(BUSY_FLAGS_NONE),
mFrameType(eFrameTypeRegular),
mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
mLoadType(0),
mMarginWidth(-1),
@ -767,7 +768,7 @@ nsDocShell::nsDocShell():
#ifdef DEBUG
mInEnsureScriptEnv(false),
#endif
mAppId(nsIScriptSecurityManager::NO_APP_ID),
mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID),
mParentCharsetSource(0)
{
mHistoryID = ++gDocshellIDCounter;
@ -2150,7 +2151,7 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
{
NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
// Content boundaries have their mFullscreenAllowed retrieved from their
// Browsers and apps have their mFullscreenAllowed retrieved from their
// corresponding iframe in their parent upon creation.
if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
*aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
@ -2160,9 +2161,9 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
// Assume false until we determine otherwise...
*aFullscreenAllowed = false;
// For non-content boundaries, check that the enclosing iframe element
// For non-browsers/apps, check that the enclosing iframe element
// has the allowfullscreen attribute set to true. If any ancestor
// iframe does not have allowfullscreen=true, then fullscreen is
// iframe does not have mozallowfullscreen=true, then fullscreen is
// prohibited.
nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(GetAsSupports(this));
if (!win) {
@ -2199,7 +2200,7 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
NS_IMETHODIMP
nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
{
if (!nsIDocShell::GetIsContentBoundary()) {
if (!nsIDocShell::GetIsBrowserOrApp()) {
// Only allow setting of fullscreenAllowed on content/process boundaries.
// At non-boundaries the fullscreenAllowed attribute is calculated based on
// whether all enclosing frames have the "mozFullscreenAllowed" attribute
@ -2811,7 +2812,7 @@ nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
NS_ENSURE_ARG_POINTER(aParent);
*aParent = nullptr;
if (mIsBrowserFrame) {
if (nsIDocShell::GetIsBrowserOrApp()) {
return NS_OK;
}
@ -2933,19 +2934,11 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
return false;
}
if (targetDS && accessingDS) {
bool targetInBrowser = false, accessingInBrowser = false;
targetDS->GetIsInBrowserElement(&targetInBrowser);
accessingDS->GetIsInBrowserElement(&accessingInBrowser);
uint32_t targetAppId = 0, accessingAppId = 0;
targetDS->GetAppId(&targetAppId);
accessingDS->GetAppId(&accessingAppId);
if (targetInBrowser != accessingInBrowser ||
targetAppId != accessingAppId) {
return false;
}
if (targetDS && accessingDS &&
(targetDS->GetIsInBrowserElement() !=
accessingDS->GetIsInBrowserElement() ||
targetDS->GetAppId() != accessingDS->GetAppId())) {
return false;
}
nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
@ -5229,7 +5222,7 @@ nsDocShell::SetIsActive(bool aIsActive)
continue;
}
if (!docshell->GetIsContentBoundary()) {
if (!docshell->GetIsBrowserOrApp()) {
docshell->SetIsActive(aIsActive);
}
}
@ -12311,19 +12304,52 @@ nsDocShell::GetCanExecuteScripts(bool *aResult)
}
NS_IMETHODIMP
nsDocShell::SetIsBrowserElement()
nsDocShell::SetIsApp(uint32_t aOwnAppId)
{
if (mIsBrowserFrame) {
NS_ERROR("You should not call SetIsBrowserElement() more than once.");
return NS_OK;
mOwnOrContainingAppId = aOwnAppId;
if (aOwnAppId != nsIScriptSecurityManager::NO_APP_ID &&
aOwnAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
mFrameType = eFrameTypeApp;
} else {
mFrameType = eFrameTypeRegular;
}
mIsBrowserFrame = true;
return NS_OK;
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->NotifyObservers(GetAsSupports(this),
"docshell-marked-as-browser-frame", NULL);
NS_IMETHODIMP
nsDocShell::SetIsBrowserInsideApp(uint32_t aContainingAppId)
{
mOwnOrContainingAppId = aContainingAppId;
mFrameType = eFrameTypeBrowser;
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
{
*aIsBrowser = (mFrameType == eFrameTypeBrowser);
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsApp(bool* aIsApp)
{
*aIsApp = (mFrameType == eFrameTypeApp);
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsBrowserOrApp(bool* aIsBrowserOrApp)
{
switch (mFrameType) {
case eFrameTypeRegular:
*aIsBrowserOrApp = false;
break;
case eFrameTypeBrowser:
case eFrameTypeApp:
*aIsBrowserOrApp = true;
break;
}
return NS_OK;
@ -12332,10 +12358,8 @@ nsDocShell::SetIsBrowserElement()
nsDocShell::FrameType
nsDocShell::GetInheritedFrameType()
{
FrameType type = GetFrameType();
if (type != eFrameTypeRegular) {
return type;
if (mFrameType != eFrameTypeRegular) {
return mFrameType;
}
nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
@ -12349,46 +12373,6 @@ nsDocShell::GetInheritedFrameType()
return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
}
nsDocShell::FrameType
nsDocShell::GetFrameType()
{
if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
return eFrameTypeApp;
}
return mIsBrowserFrame ? eFrameTypeBrowser : eFrameTypeRegular;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
{
*aIsBrowser = (GetFrameType() == eFrameTypeBrowser);
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsApp(bool* aIsApp)
{
*aIsApp = (GetFrameType() == eFrameTypeApp);
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsContentBoundary(bool* aIsContentBoundary)
{
switch (GetFrameType()) {
case eFrameTypeRegular:
*aIsContentBoundary = false;
break;
case eFrameTypeBrowser:
case eFrameTypeApp:
*aIsContentBoundary = true;
break;
}
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement)
{
@ -12397,50 +12381,29 @@ nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement)
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsInApp(bool* aIsInApp)
{
*aIsInApp = (GetInheritedFrameType() == eFrameTypeApp);
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsBelowContentBoundary(bool* aIsInContentBoundary)
nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp)
{
switch (GetInheritedFrameType()) {
case eFrameTypeRegular:
*aIsInContentBoundary = false;
*aIsInBrowserOrApp = false;
break;
case eFrameTypeBrowser:
case eFrameTypeApp:
*aIsInContentBoundary = true;
*aIsInBrowserOrApp = true;
break;
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetAppId(uint32_t aAppId)
{
MOZ_ASSERT(mAppId == nsIScriptSecurityManager::NO_APP_ID);
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
mAppId = aAppId;
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetAppId(uint32_t* aAppId)
{
if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
MOZ_ASSERT(GetFrameType() == eFrameTypeApp);
*aAppId = mAppId;
if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
*aAppId = mOwnOrContainingAppId;
return NS_OK;
}
MOZ_ASSERT(GetFrameType() != eFrameTypeApp);
nsCOMPtr<nsIDocShell> parent;
GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));

View File

@ -665,13 +665,12 @@ protected:
bool JustStartedNetworkLoad();
enum FrameType {
eFrameTypeRegular = 0x0, // 0000
eFrameTypeBrowser = 0x1, // 0001
eFrameTypeApp = 0x2 // 0010
eFrameTypeRegular,
eFrameTypeBrowser,
eFrameTypeApp
};
FrameType GetInheritedFrameType();
FrameType GetFrameType();
// hash of session storages, keyed by domain
nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;
@ -808,7 +807,6 @@ protected:
bool mIsAppTab;
bool mUseGlobalHistory;
bool mInPrivateBrowsing;
bool mIsBrowserFrame;
// This boolean is set to true right before we fire pagehide and generally
// unset when we embed a new content viewer. While it's true no navigation
@ -845,7 +843,18 @@ protected:
nsRefPtr<nsDOMNavigationTiming> mTiming;
uint32_t mAppId;
// Are we a regular frame, a browser frame, or an app frame?
FrameType mFrameType;
// We only expect mOwnOrContainingAppId to be something other than
// UNKNOWN_APP_ID if mFrameType != eFrameTypeRegular. For vanilla iframes
// inside an app, we'll retrieve the containing app-id by walking up the
// docshell hierarchy.
//
// (This needs to be the docshell's own /or containing/ app id because the
// containing app frame might be in another process, in which case we won't
// find it by walking up the docshell hierarchy.)
uint32_t mOwnOrContainingAppId;
private:
nsCOMPtr<nsIAtom> mForcedCharset;

View File

@ -39,7 +39,7 @@ interface nsIWebBrowserPrint;
interface nsIVariant;
interface nsIPrivacyTransitionObserver;
[scriptable, builtinclass, uuid(0132C0BE-ACB5-4D61-9B19-01C005E030DA)]
[scriptable, builtinclass, uuid(318CE516-3F7A-41F6-8F3D-3661650F7A46)]
interface nsIDocShell : nsISupports
{
/**
@ -579,72 +579,88 @@ interface nsIDocShell : nsISupports
void addWeakPrivacyTransitionObserver(in nsIPrivacyTransitionObserver obs);
/**
* Mark the docshell as a browser frame.
* This should be used for <iframe mozbrowser> but not for <iframe mozapp>.
*
* This method should not be called more than once.
*/
void setIsBrowserElement();
/**
* Returns true iff the docshell is marked as a browser frame.
* Returns true if this docshell corresponds to an <iframe mozbrowser>.
* (<iframe mozapp mozbrowser> is not considered a browser.)
*/
[infallible] readonly attribute boolean isBrowserElement;
/**
* Returns true iif the docshell is marked as an app frame.
* Returns true iff the docshell corresponds to an <iframe mozapp>.
*/
[infallible] readonly attribute boolean isApp;
/**
* Returns true iif the docshell is marked as a type that behaves like a
* content boundary.
* Returns isBrowserElement || isApp.
*/
[infallible] readonly attribute boolean isContentBoundary;
[infallible] readonly attribute boolean isBrowserOrApp;
/**
* Returns true iif the docshell is inside a browser element.
* Returns true if this docshell corresponds to an <iframe mozbrowser> or if
* the docshell is contained in an <iframe mozbrowser>. (<iframe mozapp
* mozbrowser> does not count as a browser.)
*
* Our notion here of "contained in" means: Walk up the docshell hierarchy in
* this process until we hit an <iframe mozapp> or <iframe mozbrowser> (or
* until the hierarchy ends). Return true iff the docshell we stopped on has
* isBrowserElement == true.
*/
[infallible] readonly attribute boolean isInBrowserElement;
/**
* Returns true iif the docshell is inside an application. However, it will
* return false if the docshell is inside a browser element that is inside
* an application.
* Returns true if this docshell corresponds to an <iframe mozbrowser> or
* <iframe mozap>, or if this docshell is contained in an <iframe mozbrowser>
* or <iframe mozapp>.
*
* Note: Do not use this method for permissions checks! An app may contain
* an <iframe> pointing at arbitrary web code. This iframe's docshell will
* have isInApp() == true, but the iframe's content is not "app code", and
* so should not be granted more trust than vanilla web content.
*
* (For example, suppose when web content calls API method X, we show a
* permission prompt, but when "app code" calls method X, we don't. In this
* case, it would be /incorrect/ to show the permission prompt if
* !isInApp().)
*
* If you're doing a security check, use the content's principal instead of
* this method.
* To compute this value, we walk up the docshell hierarchy. If we encounter
* a docshell with isBrowserElement or isApp before we hit the end of the
* hierarchy, we return true. Otherwise, we return false.
*/
[infallible] readonly attribute boolean isInApp;
[infallible] readonly attribute boolean isInBrowserOrApp;
/**
* Indicate that this docshell corresponds to an app with the given app id.
*
* You may pass NO_APP_ID or UNKNOWN_APP_ID for containingAppId. If you
* pass NO_APP_ID, then this docshell will return NO_APP_ID for appId. If
* you pass UNKNOWN_APP_ID, then this docshell will search its hiearchy for
* an app frame and use that frame's appId.
*
* You can call this method more than once, but there's no guarantee that
* other components will update their view of the world if you change a
* docshell's app id, so tread lightly.
*
* If you call this method after calling setIsBrowserInsideApp, this
* docshell will forget the fact that it was a browser.
*/
void setIsApp(in unsigned long ownAppId);
/**
* Indicate that this docshell corresponds to a browser inside an app with
* the given ID. As with setIsApp, you may pass NO_APP_ID or
* UNKNOWN_APP_ID.
*
* As with setIsApp, you may call this more than once, but it's kind of a
* hack, so be careful.
*/
void setIsBrowserInsideApp(in unsigned long containingAppId);
/**
* Returns if the docshell has a docshell that behaves as a content boundary
* in his parent hierarchy.
*/
[infallible] readonly attribute boolean isBelowContentBoundary;
/**
* Set the app id this docshell is associated with. The id has to be a valid
* app id. If the docshell isn't associated with any app, the value should be
* nsIScriptSecurityManager::NO_APP_ID. However, this is the default value if
* nothing is et.
* Returns the id of the app associated with this docshell. If this docshell
* is an <iframe mozbrowser> inside an <iframe mozapp>, we return the app's
* appId.
*
* This method is [noscript] to reduce the scope. It should be used at very
* specific moments.
* We compute this value by walking up the docshell hierarchy until we find a
* docshell on which setIsApp(x) or setIsBrowserInsideApp(x) was called
* (ignoring those docshells where x == UNKNOWN_APP_ID). We return the app
* id x.
*
* Calling setAppId() will mark the frame as an app frame.
* If we don't find a docshell with an associated app id in our hierarchy, we
* return NO_APP_ID. We never return UNKNOWN_APP_ID.
*
* Notice that a docshell may have an associated app even if it returns true
* for isBrowserElement!
*/
[noscript] void setAppId(in unsigned long appId);
[infallible] readonly attribute unsigned long appId;
/**
* Like nsIDocShellTreeItem::GetSameTypeParent, except this ignores <iframe

View File

@ -2924,7 +2924,7 @@ nsGlobalWindow::GetScriptableParent(nsIDOMWindow** aParent)
return NS_OK;
}
if (mDocShell->GetIsContentBoundary()) {
if (mDocShell->GetIsBrowserOrApp()) {
nsCOMPtr<nsIDOMWindow> parent = static_cast<nsIDOMWindow*>(this);
parent.swap(*aParent);
return NS_OK;
@ -3029,9 +3029,9 @@ nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
*aContent = nullptr;
// If we're contained in <iframe mozbrowser>, then GetContent is the same as
// window.top.
if (mDocShell && mDocShell->GetIsBelowContentBoundary()) {
// If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
// GetContent is the same as window.top.
if (mDocShell && mDocShell->GetIsInBrowserOrApp()) {
return GetScriptableTop(aContent);
}
@ -6488,7 +6488,7 @@ nsGlobalWindow::Close()
FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
if (!mDocShell || IsInModalState() ||
(IsFrame() && !mDocShell->GetIsContentBoundary())) {
(IsFrame() && !mDocShell->GetIsBrowserOrApp())) {
// window.close() is called on a frame in a frameset, on a window
// that's already closed, or on a window for which there's
// currently a modal dialog open. Ignore such calls.
@ -7007,8 +7007,9 @@ nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
* nsIGlobalWindow::frameElement.
*
* In contrast to GetRealFrameElement, GetScriptableFrameElement says that the
* window contained by an <iframe mozbrowser> has no frame element
* (effectively treating a mozbrowser the same as a content/chrome boundary).
* window contained by an <iframe mozbrowser> or <iframe mozapp> has no frame
* element (effectively treating a mozbrowser the same as a content/chrome
* boundary).
*/
NS_IMETHODIMP
nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement** aFrameElement)
@ -7016,7 +7017,7 @@ nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement** aFrameElement)
FORWARD_TO_OUTER(GetScriptableFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
*aFrameElement = NULL;
if (!mDocShell || mDocShell->GetIsContentBoundary()) {
if (!mDocShell || mDocShell->GetIsBrowserOrApp()) {
return NS_OK;
}

View File

@ -9,7 +9,7 @@
interface nsITabParent;
[scriptable, uuid(6f043e42-02c9-4e8f-8f8d-1b83c6102827)]
[scriptable, builtinclass, uuid(929AED00-3E15-49B7-8CA2-75003715B7E7)]
interface nsIMozBrowserFrame : nsIDOMMozBrowserFrame
{
/**
@ -19,7 +19,7 @@ interface nsIMozBrowserFrame : nsIDOMMozBrowserFrame
* nsIDOMMozBrowserFrame::mozbrowser attribute must be true, and the frame
* may have to pass various security checks.
*/
readonly attribute boolean reallyIsBrowser;
[infallible] readonly attribute boolean reallyIsBrowserOrApp;
/**
* Gets whether this frame really is an app frame.
@ -28,11 +28,13 @@ interface nsIMozBrowserFrame : nsIDOMMozBrowserFrame
* frame (this requirement will go away eventually), and the frame's mozapp
* attribute must point to the manifest of a valid app.
*/
readonly attribute boolean reallyIsApp;
[infallible] readonly attribute boolean reallyIsApp;
/**
* Gets this frame's app manifest URL, if the frame really is an app frame.
* Otherwise, returns the empty string.
*
* This method is guaranteed not to fail.
*/
readonly attribute AString appManifestURL;

View File

@ -27,7 +27,7 @@ AssertAppProcessPermission(PBrowserParent* aActor, const char* aPermission)
}
TabParent* tab = static_cast<TabParent*>(aActor);
nsCOMPtr<mozIApplication> app = tab->GetApp();
nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
bool hasPermission = false;
// isBrowser frames inherit their app descriptor to identify their

View File

@ -231,13 +231,11 @@ ConsoleListener::Observe(nsIConsoleMessage* aMessage)
ContentChild* ContentChild::sSingleton;
ContentChild::ContentChild()
:
mID(uint64_t(-1))
: TabContext()
, mID(uint64_t(-1))
#ifdef ANDROID
,mScreenSize(0, 0)
#endif
, mIsForApp(false)
, mIsForBrowser(false)
{
// This process is a content process, so it's clearly running in
// multiprocess mode!
@ -301,7 +299,7 @@ ContentChild::Init(MessageLoop* aIOLoop,
startBackground ? hal::PROCESS_PRIORITY_BACKGROUND:
hal::PROCESS_PRIORITY_FOREGROUND);
if (mIsForApp && !mIsForBrowser) {
SetProcessName(NS_LITERAL_STRING("(App)"));
SetProcessName(NS_LITERAL_STRING("(Preallocated app)"));
} else {
SetProcessName(NS_LITERAL_STRING("Browser"));
}
@ -489,8 +487,8 @@ static void FirstIdle(void)
}
PBrowserChild*
ContentChild::AllocPBrowser(const uint32_t& aChromeFlags,
const bool& aIsBrowserElement, const AppId& aApp)
ContentChild::AllocPBrowser(const IPCTabContext& aContext,
const uint32_t& aChromeFlags)
{
static bool firstIdleTaskPosted = false;
if (!firstIdleTaskPosted) {
@ -498,8 +496,12 @@ ContentChild::AllocPBrowser(const uint32_t& aChromeFlags,
firstIdleTaskPosted = true;
}
nsRefPtr<TabChild> child =
TabChild::Create(aChromeFlags, aIsBrowserElement, aApp.get_uint32_t());
// We'll happily accept any kind of IPCTabContext here; we don't need to
// check that it's of a certain type for security purposes, because we
// believe whatever the parent process tells us.
nsRefPtr<TabChild> child = TabChild::Create(TabContext(aContext), aChromeFlags);
// The ref here is released below.
return child.forget().get();
}

View File

@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/PContentChild.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/dom/ipc/Blob.h"
#include "nsTArray.h"
@ -40,6 +41,7 @@ class PStorageChild;
class ClonedMessageData;
class ContentChild : public PContentChild
, public TabContext
{
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
@ -78,9 +80,8 @@ public:
AllocPImageBridge(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
virtual PBrowserChild* AllocPBrowser(const uint32_t& aChromeFlags,
const bool& aIsBrowserElement,
const AppId& aAppId);
virtual PBrowserChild* AllocPBrowser(const IPCTabContext &aContext,
const uint32_t &chromeFlags);
virtual bool DeallocPBrowser(PBrowserChild*);
virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequest(const DeviceStorageParams&);
@ -195,9 +196,6 @@ public:
uint64_t GetID() { return mID; }
bool IsForApp() { return mIsForApp; }
bool IsForBrowser() { return mIsForBrowser; }
BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
private:

View File

@ -55,7 +55,6 @@
#include "nsFrameMessageManager.h"
#include "nsHashPropertyBag.h"
#include "nsIAlertsService.h"
#include "nsIAppsService.h"
#include "nsIClipboard.h"
#include "nsIDOMApplicationRegistry.h"
#include "nsIDOMGeoGeolocation.h"
@ -317,27 +316,25 @@ AppNeedsInheritedOSPrivileges(mozIApplication* aApp)
}
/*static*/ TabParent*
ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
ContentParent::CreateBrowserOrApp(const TabContext& aContext)
{
// We currently don't set the <app> ancestor for <browser> content
// correctly. This assertion is to notify the person who fixes
// this code that they need to reevaluate places here where we may
// make bad assumptions based on that bug.
MOZ_ASSERT(!aApp || !aIsBrowserElement);
if (!aApp) {
if (ContentParent* cp = GetNewOrUsed(aIsBrowserElement)) {
nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
return static_cast<TabParent*>(
cp->SendPBrowserConstructor(
// DeallocPBrowserParent() releases the ref we take here
tp.forget().get(),
/*chromeFlags*/0,
aIsBrowserElement, nsIScriptSecurityManager::NO_APP_ID));
if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
if (ContentParent* cp = GetNewOrUsed(aContext.IsBrowserElement())) {
nsRefPtr<TabParent> tp(new TabParent(aContext));
PBrowserParent* browser = cp->SendPBrowserConstructor(
tp.forget().get(), // DeallocPBrowserParent() releases this ref.
aContext.AsIPCTabContext(),
/* chromeFlags */ 0);
return static_cast<TabParent*>(browser);
}
return nullptr;
}
// If we got here, we have an app and we're not a browser element. ownApp
// shouldn't be null, because we otherwise would have gone into the
// !HasOwnApp() branch above.
nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp();
if (!gAppContentParents) {
gAppContentParents =
new nsDataHashtable<nsStringHashKey, ContentParent*>();
@ -346,29 +343,15 @@ ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
// Each app gets its own ContentParent instance.
nsAutoString manifestURL;
if (NS_FAILED(aApp->GetManifestURL(manifestURL))) {
if (NS_FAILED(ownApp->GetManifestURL(manifestURL))) {
NS_ERROR("Failed to get manifest URL");
return nullptr;
}
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (!appsService) {
NS_ERROR("Failed to get apps service");
return nullptr;
}
// Send the local app ID to the new TabChild so it knows what app
// it is.
uint32_t appId;
if (NS_FAILED(appsService->GetAppLocalIdByManifestURL(manifestURL, &appId))) {
NS_ERROR("Failed to get local app ID");
return nullptr;
}
nsRefPtr<ContentParent> p = gAppContentParents->Get(manifestURL);
if (!p) {
if (AppNeedsInheritedOSPrivileges(aApp)) {
p = new ContentParent(manifestURL, aIsBrowserElement,
if (AppNeedsInheritedOSPrivileges(ownApp)) {
p = new ContentParent(manifestURL, /* isBrowserElement = */ false,
base::PRIVILEGES_INHERIT);
p->Init();
} else {
@ -377,7 +360,7 @@ ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
p->SetManifestFromPreallocated(manifestURL);
} else {
NS_WARNING("Unable to use pre-allocated app process");
p = new ContentParent(manifestURL, aIsBrowserElement,
p = new ContentParent(manifestURL, /* isBrowserElement = */ false,
base::PRIVILEGES_DEFAULT);
p->Init();
}
@ -385,12 +368,12 @@ ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
gAppContentParents->Put(manifestURL, p);
}
nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
return static_cast<TabParent*>(
// DeallocPBrowserParent() releases the ref we take here
p->SendPBrowserConstructor(tp.forget().get(),
/*chromeFlags*/0,
aIsBrowserElement, appId));
nsRefPtr<TabParent> tp = new TabParent(aContext);
PBrowserParent* browser = p->SendPBrowserConstructor(
tp.forget().get(), // DeallocPBrowserParent() releases this ref.
aContext.AsIPCTabContext(),
/* chromeFlags */ 0);
return static_cast<TabParent*>(browser);
}
static PLDHashOperator
@ -1163,30 +1146,37 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline)
}
PBrowserParent*
ContentParent::AllocPBrowser(const uint32_t& aChromeFlags,
const bool& aIsBrowserElement, const AppId& aApp)
ContentParent::AllocPBrowser(const IPCTabContext& aContext,
const uint32_t &aChromeFlags)
{
// We only use this Alloc() method when the content processes asks
// us to open a window. In that case, we're expecting to see the
// opening PBrowser as its app descriptor, and we can trust the data
// associated with that PBrowser since it's fully owned by this
// process.
if (AppId::TPBrowserParent != aApp.type()) {
NS_ERROR("Content process attempting to forge app ID");
return nullptr;
}
TabParent* opener = static_cast<TabParent*>(aApp.get_PBrowserParent());
unused << aChromeFlags;
// Popup windows of isBrowser frames are isBrowser if the parent
// isBrowser. Allocating a !isBrowser frame with same app ID
// would allow the content to access data it's not supposed to.
if (opener && opener->IsBrowserElement() && !aIsBrowserElement) {
NS_ERROR("Content process attempting to escalate data access privileges");
// We don't trust the IPCTabContext we receive from the child, so we'll bail
// if we receive an IPCTabContext that's not a PopupIPCTabContext.
// (PopupIPCTabContext lets the child process prove that it has access to
// the app it's trying to open.)
if (aContext.type() != IPCTabContext::TPopupIPCTabContext) {
NS_ERROR("Unexpected IPCTabContext type. Aborting AllocPBrowser.");
return nullptr;
}
TabParent* parent = new TabParent(opener ? opener->GetApp() : nullptr,
aIsBrowserElement);
const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
TabParent* opener = static_cast<TabParent*>(popupContext.openerParent());
if (!opener) {
NS_ERROR("Got null opener from child; aborting AllocPBrowser.");
return nullptr;
}
// Popup windows of isBrowser frames must be isBrowser if the parent
// isBrowser. Allocating a !isBrowser frame with same app ID would allow
// the content to access data it's not supposed to.
if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
NS_ERROR("Child trying to escalate privileges! Aborting AllocPBrowser.");
return nullptr;
}
TabParent* parent = new TabParent(TabContext(aContext));
// We release this ref in DeallocPBrowser()
NS_ADDREF(parent);
return parent;

View File

@ -11,6 +11,7 @@
#include "mozilla/dom/PContentParent.h"
#include "mozilla/dom/PMemoryReportRequestParent.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/Attributes.h"
@ -74,15 +75,9 @@ public:
static ContentParent* GetNewOrUsed(bool aForBrowserElement = false);
/**
* Get or create a content process for the given app descriptor,
* which may be null. This function will assign processes to app
* or non-app browsers by internal heuristics.
*
* Currently apps are given their own process, and browser tabs
* share processes.
* Get or create a content process for the given TabContext.
*/
static TabParent* CreateBrowser(mozIApplication* aApp,
bool aIsBrowserFrame);
static TabParent* CreateBrowserOrApp(const TabContext& aContext);
static void GetAll(nsTArray<ContentParent*>& aArray);
@ -189,9 +184,8 @@ private:
bool* aIsForBrowser) MOZ_OVERRIDE;
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline) MOZ_OVERRIDE;
virtual PBrowserParent* AllocPBrowser(const uint32_t& aChromeFlags,
const bool& aIsBrowserElement,
const AppId& aApp);
virtual PBrowserParent* AllocPBrowser(const IPCTabContext& aContext,
const uint32_t& aChromeFlags);
virtual bool DeallocPBrowser(PBrowserParent* frame);
virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);

View File

@ -42,6 +42,7 @@ EXPORTS_mozilla/dom = \
StructuredCloneUtils.h \
TabParent.h \
TabChild.h \
TabContext.h \
TabMessageUtils.h \
$(NULL)
@ -64,6 +65,7 @@ CPPSRCS = \
StructuredCloneUtils.cpp \
TabParent.cpp \
TabChild.cpp \
TabContext.cpp \
TabMessageUtils.cpp \
$(NULL)

View File

@ -135,9 +135,60 @@ union BlobConstructorParams
MysteryBlobConstructorParams;
};
union AppId {
uint32_t;
nullable PBrowser;
// An IPCTabContext which corresponds to a PBrowser opened by a child when it
// receives window.open().
//
// If isBrowserElement is false, this PopupIPCTabContext corresponds to an app
// frame, and the frame's app-id and app-frame-owner-app-id will be equal to the
// opener's values.
//
// If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal
// to the opener's app-id.
//
// It's an error to set isBrowserElement == false if opener is a browser
// element. Such a PopupIPCTabContext should be rejected by code which receives
// it.
struct PopupIPCTabContext
{
PBrowser opener;
bool isBrowserElement;
};
// An IPCTabContext which corresponds to an app frame.
struct AppFrameIPCTabContext
{
// The ID of the app this frame corresponds to. May be NO_APP_ID.
uint32_t ownAppId;
// The ID of the app containing this frame. May be NO_APP_ID.
uint32_t appFrameOwnerAppId;
};
// An IPCTabContext which corresponds to a browser frame.
struct BrowserFrameIPCTabContext
{
// The ID of the app which contains this browser frame. May be NO_APP_ID.
uint32_t browserFrameOwnerAppId;
};
// This is equivalent to AppFrameIPCTabContext with all fields set to NO_APP_ID.
struct VanillaFrameIPCTabContext
{};
// IPCTabContext is an analog to mozilla::dom::TabContext. Both specify an
// iframe/PBrowser's own and containing app-ids and tell you whether the
// iframe/PBrowser is a browser frame. But only IPCTabContext is allowed to
// travel over IPC.
//
// We need IPCTabContext (specifically, PopupIPCTabContext) to prevent a
// privilege escalation attack by a compromised child process. See the comment
// on AllocPBrowser for details.
union IPCTabContext
{
PopupIPCTabContext;
AppFrameIPCTabContext;
BrowserFrameIPCTabContext;
VanillaFrameIPCTabContext;
};
union PrefValue {
@ -182,16 +233,26 @@ both:
// created from either the child or parent process!
//
// The child creates the PBrowser as part of
// TabChild::BrowserFrameProvideWindow, and the parent creates the
// PBrowser as part of ContentParent::CreateTab.
// TabChild::BrowserFrameProvideWindow (which happens when the child's
// content calls window.open()), and the parent creates the PBrowser as part
// of ContentParent::CreateTab.
//
// When the parent constructs a PBrowser, the app ID handed to the
// child side is trusted. In that case, |appId| is uint32_t.
// However, when the child side constructs a PBrowser, for
// window.open(), the parent must validate the app ID used on the
// parent side. To do so, the child process must pass a valid
// PBrowser as its |AppId|.
async PBrowser(uint32_t chromeFlags, bool isBrowserElement, AppId appId);
// When the parent constructs a PBrowser, the child trusts the app token it
// receives from the parent. In that case, context can be any of the
// IPCTabContext subtypes.
//
// When the child constructs a PBrowser, the parent doesn't trust the app
// token it receives from the child. In this case, context must have type
// PopupIPCTabContext. The browser created using a PopupIPCTabContext has
// the opener PBrowser's app-id and containing-app-id. The parent checks
// that if the opener is a browser element, the context is also for a
// browser element.
//
// This allows the parent to prevent a malicious child from escalating its
// privileges by requesting a PBrowser corresponding to a highly-privileged
// app; the child can only request privileges for an app which the child has
// access to (in the form of a TabChild).
async PBrowser(IPCTabContext context, uint32_t chromeFlags);
async PBlob(BlobConstructorParams params);

View File

@ -120,8 +120,7 @@ TabChild::PreloadSlowThings()
{
MOZ_ASSERT(!sPreallocatedTab);
nsRefPtr<TabChild> tab(new TabChild(0, false,
nsIScriptSecurityManager::NO_APP_ID));
nsRefPtr<TabChild> tab(new TabChild(TabContext(), /* chromeFlags */ 0));
if (!NS_SUCCEEDED(tab->Init()) ||
!tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
return;
@ -133,41 +132,37 @@ TabChild::PreloadSlowThings()
}
/*static*/ already_AddRefed<TabChild>
TabChild::Create(uint32_t aChromeFlags,
bool aIsBrowserElement, uint32_t aAppId)
TabChild::Create(const TabContext &aContext, uint32_t aChromeFlags)
{
if (sPreallocatedTab &&
sPreallocatedTab->mChromeFlags == aChromeFlags &&
(aIsBrowserElement ||
aAppId != nsIScriptSecurityManager::NO_APP_ID)) {
aContext.IsBrowserOrApp()) {
nsRefPtr<TabChild> child = sPreallocatedTab.get();
sPreallocatedTab = nullptr;
MOZ_ASSERT(!child->mTriedBrowserInit);
child->SetAppBrowserConfig(aIsBrowserElement, aAppId);
child->SetTabContext(aContext);
child->NotifyTabContextUpdated();
return child.forget();
}
nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement,
aAppId);
nsRefPtr<TabChild> iframe = new TabChild(aContext, aChromeFlags);
return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
}
TabChild::TabChild(uint32_t aChromeFlags, bool aIsBrowserElement,
uint32_t aAppId)
: mRemoteFrame(nullptr)
TabChild::TabChild(const TabContext& aContext, uint32_t aChromeFlags)
: TabContext(aContext)
, mRemoteFrame(nullptr)
, mTabChildGlobal(nullptr)
, mChromeFlags(aChromeFlags)
, mOuterRect(0, 0, 0, 0)
, mInnerSize(0, 0)
, mOldViewportWidth(0.0f)
, mLastBackgroundColor(NS_RGB(255, 255, 255))
, mAppId(aAppId)
, mDidFakeShow(false)
, mIsBrowserElement(aIsBrowserElement)
, mNotified(false)
, mContentDocumentIsDisplayed(false)
, mTriedBrowserInit(false)
@ -530,7 +525,7 @@ TabChild::Init()
baseWindow->InitWindow(0, mWidget, 0, 0, 0, 0);
baseWindow->Create();
SetAppBrowserConfig(mIsBrowserElement, mAppId);
NotifyTabContextUpdated();
// IPC uses a WebBrowser object for which DNS prefetching is turned off
// by default. But here we really want it, so enable it explicitly
@ -554,18 +549,18 @@ TabChild::Init()
}
void
TabChild::SetAppBrowserConfig(bool aIsBrowserElement, uint32_t aAppId)
TabChild::NotifyTabContextUpdated()
{
mIsBrowserElement = aIsBrowserElement;
mAppId = aAppId;
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWebNav);
MOZ_ASSERT(docShell);
if (docShell) {
docShell->SetAppId(mAppId);
if (mIsBrowserElement) {
docShell->SetIsBrowserElement();
// nsDocShell will do the right thing if we pass NO_APP_ID or
// UNKNOWN_APP_ID for aOwnOrContainingAppId.
if (IsBrowserElement()) {
docShell->SetIsBrowserInsideApp(BrowserOwnerAppId());
} else {
docShell->SetIsApp(OwnAppId());
}
}
}
@ -789,11 +784,11 @@ TabChild::ProvideWindow(nsIDOMWindow* aParent, uint32_t aChromeFlags,
{
*aReturn = nullptr;
// If aParent is inside an <iframe mozbrowser> and this isn't a request to
// open a modal-type window, we're going to create a new <iframe mozbrowser>
// and return its window here.
// If aParent is inside an <iframe mozbrowser> or <iframe mozapp> and this
// isn't a request to open a modal-type window, we're going to create a new
// <iframe mozbrowser/mozapp> and return its window here.
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
if (docshell && docshell->GetIsBelowContentBoundary() &&
if (docshell && docshell->GetIsInBrowserOrApp() &&
!(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
@ -828,16 +823,25 @@ TabChild::BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
{
*aReturn = nullptr;
uint32_t chromeFlags = 0;
nsRefPtr<TabChild> newChild = new TabChild(chromeFlags,
mIsBrowserElement, mAppId);
nsRefPtr<TabChild> newChild =
new TabChild(/* TabContext */ *this, /* chromeFlags */ 0);
if (!NS_SUCCEEDED(newChild->Init())) {
return NS_ERROR_ABORT;
}
// We must use PopupIPCTabContext here; ContentParent will not accept the
// result of this->AsIPCTabContext() (which will be a
// BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
// reasons.
PopupIPCTabContext context;
context.openerChild() = this;
context.isBrowserElement() = IsBrowserElement();
unused << Manager()->SendPBrowserConstructor(
// We release this ref in DeallocPBrowserChild
nsRefPtr<TabChild>(newChild).forget().get(),
chromeFlags, mIsBrowserElement, this);
context, /* chromeFlags */ 0);
nsAutoCString spec;
if (aURI) {
aURI->GetSpec(spec);
@ -998,29 +1002,13 @@ TabChild::~TabChild()
void
TabChild::SetProcessNameToAppName()
{
if (mIsBrowserElement || (mAppId == nsIScriptSecurityManager::NO_APP_ID)) {
return;
}
nsCOMPtr<nsIAppsService> appsService =
do_GetService(APPS_SERVICE_CONTRACTID);
if (!appsService) {
NS_WARNING("No AppsService");
return;
}
nsresult rv;
nsCOMPtr<mozIDOMApplication> domApp;
rv = appsService->GetAppByLocalId(mAppId, getter_AddRefs(domApp));
if (NS_FAILED(rv) || !domApp) {
NS_WARNING("GetAppByLocalId failed");
return;
}
nsCOMPtr<mozIApplication> app = do_QueryInterface(domApp);
nsCOMPtr<mozIApplication> app = GetOwnApp();
if (!app) {
NS_WARNING("app isn't a mozIApplication");
return;
}
nsAutoString appName;
rv = app->GetName(appName);
nsresult rv = app->GetName(appName);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to retrieve app name");
return;
@ -1032,19 +1020,25 @@ TabChild::SetProcessNameToAppName()
bool
TabChild::IsRootContentDocument()
{
if (mIsBrowserElement || mAppId == nsIScriptSecurityManager::NO_APP_ID) {
// We're the child side of a browser element. This always
// behaves like a root content document.
return true;
}
// A TabChild is a "root content document" if it's
//
// - <iframe mozapp> not inside another <iframe mozapp>,
// - <iframe mozbrowser> (not mozapp), or
// - a vanilla remote frame (<html:iframe remote=true> or <xul:browser
// remote=true>).
//
// Put another way, an iframe is /not/ a "root content document" iff it's a
// mozapp inside a mozapp. (This corresponds exactly to !HasAppOwnerApp.)
//
// Note that we're lying through our teeth here (thus the scare quotes).
// <html:iframe remote=true> or <xul:browser remote=true> inside another
// content iframe is not actually a root content document, but we say it is.
//
// We do this because we make a remote frame opaque iff
// IsRootContentDocument(), and making vanilla remote frames transparent
// breaks our remote reftests.
// Otherwise, we're the child side of an <html:app remote=true>
// embedded in an outer <html:app>. These don't behave like root
// content documents in nested contexts. Because of bug 761935,
// <html:browser remote> and <html:app remote> can't nest, so we
// assume this isn't the root. When that bug is fixed, we need to
// revisit that assumption.
return false;
return !HasAppOwnerApp();
}
bool
@ -1702,7 +1696,7 @@ TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
mTriedBrowserInit = true;
// Initialize the child side of the browser element machinery,
// if appropriate.
if (mIsBrowserElement || mAppId != nsIScriptSecurityManager::NO_APP_ID) {
if (IsBrowserOrApp()) {
RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT);
}
}

View File

@ -51,6 +51,7 @@
#include "mozilla/Attributes.h"
#include "FrameMetrics.h"
#include "ProcessUtils.h"
#include "mozilla/dom/TabContext.h"
struct gfxMatrix;
@ -149,7 +150,8 @@ class TabChild : public PBrowserChild,
public nsIDialogCreator,
public nsITabChild,
public nsIObserver,
public mozilla::dom::ipc::MessageManagerCallback
public ipc::MessageManagerCallback,
public TabContext
{
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@ -164,12 +166,10 @@ public:
/** Return a TabChild with the given attributes. */
static already_AddRefed<TabChild>
Create(uint32_t aChromeFlags, bool aIsBrowserElement, uint32_t aAppId);
Create(const TabContext& aContext, uint32_t aChromeFlags);
virtual ~TabChild();
uint32_t GetAppId() { return mAppId; }
bool IsRootContentDocument();
NS_DECL_ISUPPORTS
@ -320,15 +320,21 @@ private:
/**
* Create a new TabChild object.
*
* |aIsBrowserElement| indicates whether the tab is inside an <iframe mozbrowser>.
* |aAppId| is the app id of the app containing this tab. If the tab isn't
* contained in an app, aAppId will be nsIScriptSecurityManager::NO_APP_ID.
* |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
* frame in the hierarchy which contains us.
*
* |aIsBrowserElement| indicates whether we're a browser (but not an app).
*/
TabChild(uint32_t aChromeFlags, bool aIsBrowserElement, uint32_t aAppId);
TabChild(const TabContext& aContext, uint32_t aChromeFlags);
nsresult Init();
void SetAppBrowserConfig(bool aIsBrowserElement, uint32_t aAppId);
// Notify others that our TabContext has been updated. (At the moment, this
// sets the appropriate app-id and is-browser flags on our docshell.)
//
// You should call this after calling TabContext::SetTabContext(). We also
// call this during Init().
void NotifyTabContextUpdated();
bool UseDirectCompositor();
@ -392,9 +398,7 @@ private:
float mOldViewportWidth;
nscolor mLastBackgroundColor;
ScrollingBehavior mScrolling;
uint32_t mAppId;
bool mDidFakeShow;
bool mIsBrowserElement;
bool mNotified;
bool mContentDocumentIsDisplayed;
bool mTriedBrowserInit;

292
dom/ipc/TabContext.cpp Normal file
View File

@ -0,0 +1,292 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/TabContext.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/dom/TabChild.h"
#include "nsIAppsService.h"
using namespace mozilla::dom::ipc;
namespace mozilla {
namespace dom {
TabContext::TabContext()
: mInitialized(false)
, mOwnAppId(nsIScriptSecurityManager::NO_APP_ID)
, mContainingAppId(nsIScriptSecurityManager::NO_APP_ID)
, mIsBrowser(false)
{
}
TabContext::TabContext(const IPCTabContext& aParams)
: mInitialized(true)
{
switch(aParams.type()) {
case IPCTabContext::TPopupIPCTabContext: {
const PopupIPCTabContext &ipcContext = aParams.get_PopupIPCTabContext();
TabContext *context;
if (ipcContext.openerParent()) {
context = static_cast<TabParent*>(ipcContext.openerParent());
if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) {
// If the TabParent corresponds to a browser element, then it can only
// open other browser elements, for security reasons. We should have
// checked this before calling the TabContext constructor, so this is
// a fatal error.
MOZ_CRASH();
}
}
else if (ipcContext.openerChild()) {
context = static_cast<TabChild*>(ipcContext.openerChild());
}
else {
// This should be unreachable because PopupIPCTabContext::opener is not a
// nullable field.
MOZ_CRASH();
}
// If ipcContext is a browser element, then the opener's app-id becomes
// our containing app-id. Otherwise, our own and containing app-ids are
// directly inherited from our opener.
if (ipcContext.isBrowserElement()) {
mIsBrowser = true;
mOwnAppId = nsIScriptSecurityManager::NO_APP_ID;
mContainingAppId = context->OwnAppId();
}
else {
mIsBrowser = false;
mOwnAppId = context->mOwnAppId;
mContainingAppId = context->mContainingAppId;
}
break;
}
case IPCTabContext::TAppFrameIPCTabContext: {
const AppFrameIPCTabContext &ipcContext =
aParams.get_AppFrameIPCTabContext();
mIsBrowser = false;
mOwnAppId = ipcContext.ownAppId();
mContainingAppId = ipcContext.appFrameOwnerAppId();
break;
}
case IPCTabContext::TBrowserFrameIPCTabContext: {
const BrowserFrameIPCTabContext &ipcContext =
aParams.get_BrowserFrameIPCTabContext();
mIsBrowser = true;
mOwnAppId = nsIScriptSecurityManager::NO_APP_ID;
mContainingAppId = ipcContext.browserFrameOwnerAppId();
break;
}
case IPCTabContext::TVanillaFrameIPCTabContext: {
mIsBrowser = false;
mOwnAppId = nsIScriptSecurityManager::NO_APP_ID;
mContainingAppId = nsIScriptSecurityManager::NO_APP_ID;
break;
}
default: {
MOZ_CRASH();
}
}
}
bool
TabContext::IsBrowserElement() const
{
return mIsBrowser;
}
bool
TabContext::IsBrowserOrApp() const
{
return HasOwnApp() || IsBrowserElement();
}
uint32_t
TabContext::OwnAppId() const
{
return mOwnAppId;
}
already_AddRefed<mozIApplication>
TabContext::GetOwnApp() const
{
return GetAppForId(OwnAppId());
}
bool
TabContext::HasOwnApp() const
{
return mOwnAppId != nsIScriptSecurityManager::NO_APP_ID;
}
uint32_t
TabContext::BrowserOwnerAppId() const
{
if (mIsBrowser) {
return mContainingAppId;
}
return nsIScriptSecurityManager::NO_APP_ID;
}
already_AddRefed<mozIApplication>
TabContext::GetBrowserOwnerApp() const
{
return GetAppForId(BrowserOwnerAppId());
}
bool
TabContext::HasBrowserOwnerApp() const
{
return BrowserOwnerAppId() != nsIScriptSecurityManager::NO_APP_ID;
}
uint32_t
TabContext::AppOwnerAppId() const
{
if (mOwnAppId != nsIScriptSecurityManager::NO_APP_ID) {
return mContainingAppId;
}
return nsIScriptSecurityManager::NO_APP_ID;
}
already_AddRefed<mozIApplication>
TabContext::GetAppOwnerApp() const
{
return GetAppForId(AppOwnerAppId());
}
bool
TabContext::HasAppOwnerApp() const
{
return AppOwnerAppId() != nsIScriptSecurityManager::NO_APP_ID;
}
uint32_t
TabContext::OwnOrContainingAppId() const
{
if (mIsBrowser) {
MOZ_ASSERT(mOwnAppId == nsIScriptSecurityManager::NO_APP_ID);
return mContainingAppId;
}
if (mOwnAppId) {
return mOwnAppId;
}
return mContainingAppId;
}
already_AddRefed<mozIApplication>
TabContext::GetOwnOrContainingApp() const
{
return GetAppForId(OwnOrContainingAppId());
}
bool
TabContext::HasOwnOrContainingApp() const
{
return OwnOrContainingAppId() != nsIScriptSecurityManager::NO_APP_ID;
}
bool
TabContext::SetTabContext(const TabContext& aContext)
{
NS_ENSURE_FALSE(mInitialized, false);
// Verify that we can actually get apps for the given ids. This step gives us
// confidence that HasX() returns true iff GetX() returns true.
if (aContext.mOwnAppId != nsIScriptSecurityManager::NO_APP_ID) {
nsCOMPtr<mozIApplication> app = GetAppForId(aContext.mOwnAppId);
NS_ENSURE_TRUE(app, false);
}
if (aContext.mContainingAppId != nsIScriptSecurityManager::NO_APP_ID) {
nsCOMPtr<mozIApplication> app = GetAppForId(aContext.mContainingAppId);
NS_ENSURE_TRUE(app, false);
}
mInitialized = true;
mIsBrowser = aContext.mIsBrowser;
mOwnAppId = aContext.mOwnAppId;
mContainingAppId = aContext.mContainingAppId;
return true;
}
bool
TabContext::SetTabContextForAppFrame(mozIApplication* aOwnApp, mozIApplication* aAppFrameOwnerApp)
{
NS_ENSURE_FALSE(mInitialized, false);
// Get ids for both apps and only write to our member variables after we've
// verified that this worked.
uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
if (aOwnApp) {
nsresult rv = aOwnApp->GetLocalId(&ownAppId);
NS_ENSURE_SUCCESS(rv, false);
}
uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
if (aAppFrameOwnerApp) {
nsresult rv = aOwnApp->GetLocalId(&containingAppId);
NS_ENSURE_SUCCESS(rv, false);
}
mInitialized = true;
mIsBrowser = false;
mOwnAppId = ownAppId;
mContainingAppId = containingAppId;
return true;
}
bool
TabContext::SetTabContextForBrowserFrame(mozIApplication* aBrowserFrameOwnerApp)
{
NS_ENSURE_FALSE(mInitialized, false);
uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
if (aBrowserFrameOwnerApp) {
nsresult rv = aBrowserFrameOwnerApp->GetLocalId(&containingAppId);
NS_ENSURE_SUCCESS(rv, false);
}
mInitialized = true;
mIsBrowser = true;
mOwnAppId = nsIScriptSecurityManager::NO_APP_ID;
mContainingAppId = containingAppId;
return true;
}
IPCTabContext
TabContext::AsIPCTabContext() const
{
if (mIsBrowser) {
return BrowserFrameIPCTabContext(mContainingAppId);
}
return AppFrameIPCTabContext(mOwnAppId, mContainingAppId);
}
already_AddRefed<mozIApplication>
TabContext::GetAppForId(uint32_t aAppId) const
{
if (aAppId == nsIScriptSecurityManager::NO_APP_ID) {
return nullptr;
}
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(appsService, nullptr);
nsCOMPtr<mozIDOMApplication> domApp;
appsService->GetAppByLocalId(aAppId, getter_AddRefs(domApp));
nsCOMPtr<mozIApplication> app = do_QueryInterface(domApp);
return app.forget();
}
} // namespace dom
} // namespace mozilla

209
dom/ipc/TabContext.h Normal file
View File

@ -0,0 +1,209 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_TabContext_h
#define mozilla_dom_TabContext_h
#include "mozilla/Assertions.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/PBrowser.h"
#include "nsIScriptSecurityManager.h"
#include "mozIApplication.h"
namespace mozilla {
namespace dom {
/**
* TabContext encapsulates information about an iframe that may be a mozbrowser
* or mozapp. You can ask whether a TabContext correspodns to a mozbrowser or
* mozapp, get the app that contains the browser, and so on.
*
* TabParent and TabChild both inherit from TabContext, and you can also have
* standalone TabContext objects.
*
* This class is immutable except by calling one of the protected
* SetTabContext*() methods (and those methods can only be called once). See
* also MutableTabContext.
*/
class TabContext
{
public:
/**
* This constructor sets is-browser to false, and sets all relevant apps to
* NO_APP_ID. If you inherit from TabContext, you can mutate this object
* exactly once by calling one of the protected SetTabContext*() methods.
*/
TabContext();
/**
* This constructor copies the information in aContext. The TabContext is
* immutable after calling this method; you won't be able call any of the
* protected SetTabContext*() methods on an object constructed using this
* constructor.
*
* If aContext is a PopupIPCTabContext with isBrowserElement false and whose
* openerParent is a browser element, this constructor will crash (even in
* release builds). So please check that case before calling this method.
*/
TabContext(const IPCTabContext& aContext);
/**
* Generates IPCTabContext of type BrowserFrameIPCTabContext or
* AppFrameIPCTabContext from this TabContext's information.
*/
IPCTabContext AsIPCTabContext() const;
/**
* Does this TabContext correspond to a mozbrowser? (<iframe mozbrowser
* mozapp> is not a browser.)
*
* If IsBrowserElement() is true, HasOwnApp() and HasAppOwnerApp() are
* guaranteed to be false.
*
* If IsBrowserElement() is false, HasBrowserOwnerApp() is guaranteed to be
* false.
*/
bool IsBrowserElement() const;
/**
* Does this TabContext correspond to a mozbrowser or mozapp? This is
* equivalent to IsBrowserElement() || HasOwnApp().
*/
bool IsBrowserOrApp() const;
/**
* OwnAppId() returns the id of the app which directly corresponds to this
* context's frame. GetOwnApp() returns the corresponding app object, and
* HasOwnApp() returns true iff GetOwnApp() would return a non-null value.
*
* If HasOwnApp() is true, IsBrowserElement() is guaranteed to be false.
*/
uint32_t OwnAppId() const;
already_AddRefed<mozIApplication> GetOwnApp() const;
bool HasOwnApp() const;
/**
* BrowserOwnerAppId() gets the ID of the app which contains this browser
* frame. If this is not a browser frame (i.e., if !IsBrowserElement()), then
* BrowserOwnerAppId() is guaranteed to return NO_APP_ID.
*
* Even if we are a browser frame, BrowserOwnerAppId() may still return
* NO_APP_ID, if this browser frame is not contained inside an app.
*/
uint32_t BrowserOwnerAppId() const;
already_AddRefed<mozIApplication> GetBrowserOwnerApp() const;
bool HasBrowserOwnerApp() const;
/**
* AppOwnerAppId() gets the ID of the app which contains this app frame. If
* this is not an app frame (i.e., if !HasOwnApp()), then AppOwnerAppId() is
* guaranteed to return NO_APP_ID.
*
* Even if we are an app frame, AppOwnerAppId() may still return NO_APP_ID, if
* this app frame is not contained inside an app.
*/
uint32_t AppOwnerAppId() const;
already_AddRefed<mozIApplication> GetAppOwnerApp() const;
bool HasAppOwnerApp() const;
/**
* OwnOrContainingAppId() gets the ID of this frame, if HasOwnApp(). If this
* frame does not have its own app, it gets the ID of the app which contains
* this frame (i.e., the result of {Browser,App}OwnerAppId(), as applicable).
*/
uint32_t OwnOrContainingAppId() const;
already_AddRefed<mozIApplication> GetOwnOrContainingApp() const;
bool HasOwnOrContainingApp() const;
protected:
/**
* These protected mutator methods let you modify a TabContext once. Further
* attempts to modify a given TabContext will fail (the method will return
* false).
*
* These mutators will also fail if the TabContext was created with anything
* other than the no-args constructor.
*/
/**
* Set this TabContext to match the given TabContext.
*/
bool SetTabContext(const TabContext& aContext);
/**
* Set this TabContext to be an app frame (with the given own app) inside the
* given app. Either or both apps may be null.
*/
bool SetTabContextForAppFrame(mozIApplication* aOwnApp,
mozIApplication* aAppFrameOwnerApp);
/**
* Set this TabContext to be a browser frame inside the given app (which may
* be null).
*/
bool SetTabContextForBrowserFrame(mozIApplication* aBrowserFrameOwnerApp);
private:
/**
* Translate an appId into a mozIApplication.
*/
already_AddRefed<mozIApplication> GetAppForId(uint32_t aAppId) const;
/**
* Has this TabContext been initialized? If so, mutator methods will fail.
*/
bool mInitialized;
/**
* This TabContext's own app id. If this is something other than NO_APP_ID,
* then this TabContext corresponds to an app, and mIsBrowser must be false.
*/
uint32_t mOwnAppId;
/**
* The id of the app which contains this TabContext's frame. If mIsBrowser,
* this corresponds to the ID of the app which contains the browser frame;
* otherwise, this correspodns to the ID of the app which contains the app
* frame.
*/
uint32_t mContainingAppId;
/**
* Does this TabContext correspond to a browser element?
*
* If this is true, mOwnAppId must be NO_APP_ID.
*/
bool mIsBrowser;
};
/**
* MutableTabContext is the same as TabContext, except the mutation methods are
* public instead of protected. You can still only call these mutation methods
* once on a given object.
*/
class MutableTabContext : public TabContext
{
public:
bool SetTabContext(const TabContext& aContext)
{
return TabContext::SetTabContext(aContext);
}
bool SetTabContextForAppFrame(mozIApplication* aOwnApp, mozIApplication* aAppFrameOwnerApp)
{
return TabContext::SetTabContextForAppFrame(aOwnApp, aAppFrameOwnerApp);
}
bool SetTabContextForBrowserFrame(mozIApplication* aBrowserFrameOwnerApp)
{
return TabContext::SetTabContextForBrowserFrame(aBrowserFrameOwnerApp);
}
};
} // namespace dom
} // namespace mozilla
#endif

View File

@ -73,9 +73,9 @@ TabParent *TabParent::mIMETabParent = nullptr;
NS_IMPL_ISUPPORTS3(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI)
TabParent::TabParent(mozIApplication* aApp, bool aIsBrowserElement)
: mFrameElement(NULL)
, mApp(aApp)
TabParent::TabParent(const TabContext& aContext)
: TabContext(aContext)
, mFrameElement(NULL)
, mIMESelectionAnchor(0)
, mIMESelectionFocus(0)
, mIMEComposing(false)
@ -85,7 +85,6 @@ TabParent::TabParent(mozIApplication* aApp, bool aIsBrowserElement)
, mEventCaptureDepth(0)
, mDimensions(0, 0)
, mDPI(0)
, mIsBrowserElement(aIsBrowserElement)
, mShown(false)
{
}
@ -188,7 +187,7 @@ TabParent::AnswerCreateWindow(PBrowserParent** retval)
}
// Only non-app, non-browser processes may call CreateWindow.
if (GetApp() || IsBrowserElement()) {
if (IsBrowserOrApp()) {
return false;
}
@ -897,9 +896,9 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
// XXXbent Need to make sure we have a whitelist for chrome databases!
// Verify the appID in the origin first.
if (mApp && !aASCIIOrigin.EqualsLiteral("chrome")) {
if (mOwnOrContainingApp && !aASCIIOrigin.EqualsLiteral("chrome")) {
uint32_t appId;
rv = mApp->GetLocalId(&appId);
rv = mOwnOrContainingApp->GetLocalId(&appId);
NS_ENSURE_SUCCESS(rv, false);
if (!IndexedDatabaseManager::OriginMatchesApp(aASCIIOrigin, appId)) {
@ -1163,29 +1162,14 @@ TabParent::GetWidget() const
return widget.forget();
}
bool
TabParent::IsForMozBrowser()
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(content);
if (browserFrame) {
bool isBrowser = false;
browserFrame->GetReallyIsBrowser(&isBrowser);
return isBrowser;
}
return false;
}
bool
TabParent::UseAsyncPanZoom()
{
bool usingOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
bool asyncPanZoomEnabled =
Preferences::GetBool("layers.async-pan-zoom.enabled", false);
ContentParent* cp = static_cast<ContentParent*>(Manager());
return (usingOffMainThreadCompositing &&
!cp->IsForApp() && IsForMozBrowser() &&
asyncPanZoomEnabled);
IsBrowserElement() && asyncPanZoomEnabled);
}
void

View File

@ -12,6 +12,7 @@
#include "jsapi.h"
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/dom/PContentDialogParent.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "nsCOMPtr.h"
#include "nsIAuthPromptProvider.h"
@ -50,11 +51,12 @@ class TabParent : public PBrowserParent
, public nsITabParent
, public nsIAuthPromptProvider
, public nsISecureBrowserUI
, public TabContext
{
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
TabParent(mozIApplication* aApp, bool aIsBrowserElement);
TabParent(const TabContext& aContext);
virtual ~TabParent();
nsIDOMElement* GetOwnerElement() { return mFrameElement; }
void SetOwnerElement(nsIDOMElement* aElement);
@ -62,9 +64,6 @@ public:
void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) {
mBrowserDOMWindow = aBrowserDOMWindow;
}
mozIApplication* GetApp() { return mApp; }
bool IsBrowserElement() { return mIsBrowserElement; }
/**
* Return the TabParent that has decided it wants to capture an
@ -262,7 +261,6 @@ protected:
uint64_t* aLayersId) MOZ_OVERRIDE;
virtual bool DeallocPRenderFrame(PRenderFrameParent* aFrame) MOZ_OVERRIDE;
nsCOMPtr<mozIApplication> mApp;
// IME
static TabParent *mIMETabParent;
nsString mIMECacheText;
@ -281,7 +279,6 @@ protected:
nsIntSize mDimensions;
float mDPI;
bool mIsBrowserElement;
bool mShown;
private:
@ -289,9 +286,7 @@ private:
already_AddRefed<nsIWidget> GetWidget() const;
layout::RenderFrameParent* GetRenderFrame();
void TryCacheDPI();
// Return true iff this TabParent was created for a mozbrowser
// frame.
bool IsForMozBrowser();
// When true, we create a pan/zoom controller for our frame and
// notify it of input events targeting us.
bool UseAsyncPanZoom();

View File

@ -1633,12 +1633,8 @@ uint32_t nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow *aParent,
// Disable CHROME_OPENAS_DIALOG if the window is inside <iframe mozbrowser>.
// It's up to the embedder to interpret what dialog=1 means.
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
if (docshell) {
bool belowContentBoundary = false;
docshell->GetIsBelowContentBoundary(&belowContentBoundary);
if (belowContentBoundary) {
chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
}
if (docshell && docshell->GetIsInBrowserOrApp()) {
chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
}
return chromeFlags;

View File

@ -196,9 +196,8 @@ gfxAndroidPlatform::FontHintingEnabled()
#else
// Otherwise, enable hinting unless we're in a content process
// that might be used for non-reflowing zoom.
return (XRE_GetProcessType() != GeckoProcessType_Content ||
(ContentChild::GetSingleton()->IsForApp() &&
!ContentChild::GetSingleton()->IsForBrowser()));
return XRE_GetProcessType() != GeckoProcessType_Content ||
ContentChild::GetSingleton()->HasOwnApp();
#endif // MOZ_USING_ANDROID_JAVA_WIDGETS
}

View File

@ -851,7 +851,7 @@ nsContentTreeOwner::ProvideWindow(nsIDOMWindow* aParent,
// open a modal-type window, we're going to create a new <iframe mozbrowser>
// and return its window here.
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
if (docshell && docshell->GetIsBelowContentBoundary() &&
if (docshell && docshell->GetIsInBrowserOrApp() &&
!(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {