Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  geckoview.js   Sprache: JAVA

 
/* 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/. */


"use strict";

var { DelayedInit } = ChromeUtils.importESModule(
  "resource://gre/modules/DelayedInit.sys.mjs"
);
var { XPCOMUtils } = ChromeUtils.importESModule(
  "resource://gre/modules/XPCOMUtils.sys.mjs"
);

ChromeUtils.defineESModuleGetters(this, {
  Blocklist: "resource://gre/modules/Blocklist.sys.mjs",
  E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
  EventDispatcher: "resource://gre/modules/Messaging.sys.mjs",
  GeckoViewActorManager: "resource://gre/modules/GeckoViewActorManager.sys.mjs",
  GeckoViewSettings: "resource://gre/modules/GeckoViewSettings.sys.mjs",
  GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.sys.mjs",
  InitializationTracker: "resource://gre/modules/GeckoViewTelemetry.sys.mjs",
  RemoteSecuritySettings:
    "resource://gre/modules/psm/RemoteSecuritySettings.sys.mjs",
  SafeBrowsing: "resource://gre/modules/SafeBrowsing.sys.mjs",
  CaptchaDetectionPingUtils:
    "resource://gre/modules/CaptchaDetectionPingUtils.sys.mjs",
});

ChromeUtils.defineLazyGetter(this"WindowEventDispatcher", () =>
  EventDispatcher.for(window)
);

XPCOMUtils.defineLazyScriptGetter(
  this,
  "PrintUtils",
  "chrome://global/content/printUtils.js"
);

// This file assumes `warn` and `debug` are imported into scope
// by the child scripts.
/* global debug, warn */

/**
 * ModuleManager creates and manages GeckoView modules. Each GeckoView module
 * normally consists of a JSM module file with an optional content module file.
 * The module file contains a class that extends GeckoViewModule, and the
 * content module file contains a class that extends GeckoViewChildModule. A
 * module usually pairs with a particular GeckoSessionHandler or delegate on the
 * Java side, and automatically receives module lifetime events such as
 * initialization, change in enabled state, and change in settings.
 */

var ModuleManager = {
  get _initData() {
    return window.arguments[0].QueryInterface(Ci.nsIGeckoViewView).initData;
  },

  init(aBrowser, aModules) {
    const initData = this._initData;
    this._browser = aBrowser;
    this._settings = initData.settings;
    this._frozenSettings = Object.freeze(Object.assign({}, this._settings));

    const self = this;
    this._modules = new Map(
      (function* () {
        for (const module of aModules) {
          yield [
            module.name,
            new ModuleInfo({
              enabled: !!initData.modules[module.name],
              manager: self,
              ...module,
            }),
          ];
        }
      })()
    );

    window.document.documentElement.appendChild(aBrowser);

    // By default all layers are discarded when a browser is set to inactive.
    // GeckoView by default sets browsers to inactive every time they're not
    // visible. To avoid flickering when changing tabs, we preserve layers for
    // all loaded tabs.
    aBrowser.preserveLayers(true);
    // GeckoView browsers start off as active (for now at least).
    // See bug 1815015 for an attempt at making them start off inactive.
    aBrowser.docShellIsActive = true;

    WindowEventDispatcher.registerListener(this, [
      "GeckoView:UpdateModuleState",
      "GeckoView:UpdateInitData",
      "GeckoView:UpdateSettings",
    ]);

    this.messageManager.addMessageListener(
      "GeckoView:ContentModuleLoaded",
      this
    );

    this._moduleByActorName = new Map();
    this.forEach(module => {
      module.onInit();
      module.loadInitFrameScript();
      for (const actorName of module.actorNames) {
        this._moduleByActorName[actorName] = module;
      }
    });

    window.addEventListener("unload", () => {
      this.forEach(module => {
        module.enabled = false;
        module.onDestroy();
      });

      this._modules.clear();
    });
  },

  onPrintWindow(aParams) {
    if (!aParams.openWindowInfo.isForWindowDotPrint) {
      return PrintUtils.handleStaticCloneCreatedForPrint(
        aParams.openWindowInfo
      );
    }
    const printActor = this.window.moduleManager.getActor(
      "GeckoViewPrintDelegate"
    );
    // Prevents continually making new static browsers
    if (printActor.browserStaticClone != null) {
      throw new Error("A prior window.print is still in progress.");
    }
    const staticBrowser = PrintUtils.createParentBrowserForStaticClone(
      aParams.openWindowInfo.parent,
      aParams.openWindowInfo
    );
    printActor.browserStaticClone = staticBrowser;
    printActor.printRequest();
    return staticBrowser;
  },

  get window() {
    return window;
  },

  get browser() {
    return this._browser;
  },

  get messageManager() {
    return this._browser.messageManager;
  },

  get eventDispatcher() {
    return WindowEventDispatcher;
  },

  get settings() {
    return this._frozenSettings;
  },

  forEach(aCallback) {
    this._modules.forEach(aCallback, this);
  },

  getActor(aActorName) {
    return this.browser.browsingContext.currentWindowGlobal?.getActor(
      aActorName
    );
  },

  // Ensures that session history has been flushed before changing remoteness
  async prepareToChangeRemoteness() {
    // Session state like history is maintained at the process level so we need
    // to collect it and restore it in the other process when switching.
    // TODO: This should go away when we migrate the history to the main
    // process Bug 1507287.
    const { history } = await this.getActor("GeckoViewContent").collectState();

    // Ignore scroll and form data since we're navigating away from this page
    // anyway
    this.sessionState = { history };
  },

  willChangeBrowserRemoteness() {
    debug`WillChangeBrowserRemoteness`;

    // Now we're switching the remoteness.
    this.disabledModules = [];
    this.forEach(module => {
      if (module.enabled && module.disableOnProcessSwitch) {
        module.enabled = false;
        this.disabledModules.push(module);
      }
    });

    this.forEach(module => {
      module.onDestroyBrowser();
    });
  },

  didChangeBrowserRemoteness() {
    debug`DidChangeBrowserRemoteness`;

    this.forEach(module => {
      if (module.impl) {
        module.impl.onInitBrowser();
      }
    });

    this.messageManager.addMessageListener(
      "GeckoView:ContentModuleLoaded",
      this
    );

    this.forEach(module => {
      // We're attaching a new browser so we have to reload the frame scripts
      module.loadInitFrameScript();
    });

    this.disabledModules.forEach(module => {
      module.enabled = true;
    });
    this.disabledModules = null;
  },

  afterBrowserRemotenessChange(aSwitchId) {
    const { sessionState } = this;
    this.sessionState = null;

    sessionState.switchId = aSwitchId;

    this.getActor("GeckoViewContent").restoreState(sessionState);
    this.browser.focus();

    // Load was handled
    return true;
  },

  _updateSettings(aSettings) {
    Object.assign(this._settings, aSettings);
    this._frozenSettings = Object.freeze(Object.assign({}, this._settings));

    const windowType = aSettings.isExtensionPopup
      ? "navigator:popup"
      : "navigator:geckoview";
    window.document.documentElement.setAttribute("windowtype", windowType);

    this.forEach(module => {
      if (module.impl) {
        module.impl.onSettingsUpdate();
      }
    });
  },

  onMessageFromActor(aActorName, aMessage) {
    this._moduleByActorName[aActorName].receiveMessage(aMessage);
  },

  onEvent(aEvent, aData) {
    debug`onEvent ${aEvent} ${aData}`;
    switch (aEvent) {
      case "GeckoView:UpdateModuleState": {
        const module = this._modules.get(aData.module);
        if (module) {
          module.enabled = aData.enabled;
        }
        break;
      }

      case "GeckoView:UpdateInitData": {
        // Replace all settings during a transfer.
        const initData = this._initData;
        this._updateSettings(initData.settings);

        // Update module enabled states.
        for (const name in initData.modules) {
          const module = this._modules.get(name);
          if (module) {
            module.enabled = initData.modules[name];
          }
        }

        // Notify child of the transfer.
        this._browser.messageManager.sendAsyncMessage(aEvent);
        break;
      }

      case "GeckoView:UpdateSettings": {
        this._updateSettings(aData);
        break;
      }
    }
  },

  receiveMessage(aMsg) {
    debug`receiveMessage ${aMsg.name} ${aMsg.data}`;
    switch (aMsg.name) {
      case "GeckoView:ContentModuleLoaded": {
        const module = this._modules.get(aMsg.data.module);
        if (module) {
          module.onContentModuleLoaded();
        }
        break;
      }
    }
  },
};

/**
 * ModuleInfo is the structure used by ModuleManager to represent individual
 * modules. It is responsible for loading the module JSM file if necessary,
 * and it acts as the intermediary between ModuleManager and the module
 * object that extends GeckoViewModule.
 */

class ModuleInfo {
  /**
   * Create a ModuleInfo instance. See _loadPhase for phase object description.
   *
   * @param manager the ModuleManager instance.
   * @param name Name of the module.
   * @param enabled Enabled state of the module at startup.
   * @param onInit Phase object for the init phase, when the window is created.
   * @param onEnable Phase object for the enable phase, when the module is first
   *                 enabled by setting a delegate in Java.
   */

  constructor({ manager, name, enabled, onInit, onEnable }) {
    this._manager = manager;
    this._name = name;

    // We don't support having more than one main process script, so let's
    // check that we're not accidentally defining two. We could support this if
    // needed by making _impl an array for each phase impl.
    if (onInit?.resource !== undefined && onEnable?.resource !== undefined) {
      throw new Error(
        "Only one main process script is allowed for each module."
      );
    }

    this._impl = null;
    this._contentModuleLoaded = false;
    this._enabled = false;
    // Only enable once we performed initialization.
    this._enabledOnInit = enabled;

    // For init, load resource _before_ initializing browser to support the
    // onInitBrowser() override. However, load content module after initializing
    // browser, because we don't have a message manager before then.
    this._loadResource(onInit);
    this._loadActors(onInit);
    if (this._enabledOnInit) {
      this._loadActors(onEnable);
    }

    this._onInitPhase = onInit;
    this._onEnablePhase = onEnable;

    const actorNames = [];
    if (this._onInitPhase?.actors) {
      actorNames.push(Object.keys(this._onInitPhase.actors));
    }
    if (this._onEnablePhase?.actors) {
      actorNames.push(Object.keys(this._onEnablePhase.actors));
    }
    this._actorNames = Object.freeze(actorNames);
  }

  get actorNames() {
    return this._actorNames;
  }

  onInit() {
    if (this._impl) {
      this._impl.onInit();
      this._impl.onSettingsUpdate();
    }

    this.enabled = this._enabledOnInit;
  }

  /**
   * Loads the onInit frame script
   */

  loadInitFrameScript() {
    this._loadFrameScript(this._onInitPhase);
  }

  onDestroy() {
    if (this._impl) {
      this._impl.onDestroy();
    }
  }

  /**
   * Called before the browser is removed
   */

  onDestroyBrowser() {
    if (this._impl) {
      this._impl.onDestroyBrowser();
    }
    this._contentModuleLoaded = false;
  }

  _loadActors(aPhase) {
    if (!aPhase || !aPhase.actors) {
      return;
    }

    GeckoViewActorManager.addJSWindowActors(aPhase.actors);
  }

  /**
   * Load resource according to a phase object that contains possible keys,
   *
   * "resource": specify the JSM resource to load for this module.
   * "frameScript": specify a content JS frame script to load for this module.
   */

  _loadResource(aPhase) {
    if (!aPhase || !aPhase.resource || this._impl) {
      return;
    }

    const exports = ChromeUtils.importESModule(aPhase.resource);
    this._impl = new exports[this._name](this);
  }

  /**
   * Load frameScript according to a phase object that contains possible keys,
   *
   * "frameScript": specify a content JS frame script to load for this module.
   */

  _loadFrameScript(aPhase) {
    if (!aPhase || !aPhase.frameScript || this._contentModuleLoaded) {
      return;
    }

    if (this._impl) {
      this._impl.onLoadContentModule();
    }
    this._manager.messageManager.loadFrameScript(aPhase.frameScript, true);
    this._contentModuleLoaded = true;
  }

  get manager() {
    return this._manager;
  }

  get disableOnProcessSwitch() {
    // Only disable while process switching if it has a frameScript
    return (
      !!this._onInitPhase?.frameScript || !!this._onEnablePhase?.frameScript
    );
  }

  get name() {
    return this._name;
  }

  get impl() {
    return this._impl;
  }

  get enabled() {
    return this._enabled;
  }

  set enabled(aEnabled) {
    if (aEnabled === this._enabled) {
      return;
    }

    if (!aEnabled && this._impl) {
      this._impl.onDisable();
    }

    this._enabled = aEnabled;

    if (aEnabled) {
      this._loadResource(this._onEnablePhase);
      this._loadFrameScript(this._onEnablePhase);
      this._loadActors(this._onEnablePhase);
      if (this._impl) {
        this._impl.onEnable();
        this._impl.onSettingsUpdate();
      }
    }

    this._updateContentModuleState();
  }

  receiveMessage(aMessage) {
    if (!this._impl) {
      throw new Error(`No impl for message: ${aMessage.name}.`);
    }

    try {
      this._impl.receiveMessage(aMessage);
    } catch (error) {
      warn`this._impl.receiveMessage failed ${aMessage.name}`;
      throw error;
    }
  }

  onContentModuleLoaded() {
    this._updateContentModuleState();

    if (this._impl) {
      this._impl.onContentModuleLoaded();
    }
  }

  _updateContentModuleState() {
    this._manager.messageManager.sendAsyncMessage(
      "GeckoView:UpdateModuleState",
      {
        module: this._name,
        enabled: this.enabled,
      }
    );
  }
}

function createBrowser() {
  const browser = (window.browser = document.createXULElement("browser"));
  // Identify this `<browser>` element uniquely to Marionette, devtools, etc.
  // Use the JSM global to create the permanentKey, so that if the
  // permanentKey is held by something after this window closes, it
  // doesn't keep the window alive. See also Bug 1501789.
  browser.permanentKey = new (Cu.getGlobalForObject(Services).Object)();

  browser.setAttribute("nodefaultsrc""true");
  browser.setAttribute("type""content");
  browser.setAttribute("primary""true");
  browser.setAttribute("flex""1");
  browser.setAttribute("maychangeremoteness""true");
  browser.setAttribute("remote""true");
  browser.setAttribute("remoteType", E10SUtils.DEFAULT_REMOTE_TYPE);
  browser.setAttribute("messagemanagergroup""browsers");
  browser.setAttribute("manualactiveness""true");

  // This is only needed for mochitests, so that they honor the
  // prefers-color-scheme.content-override pref. GeckoView doesn't set this
  // pref to anything other than the default value otherwise.
  browser.setAttribute(
    "style",
    "color-scheme: env(-moz-content-preferred-color-scheme)"
  );

  return browser;
}

function InitLater(fn, object, name) {
  return DelayedInit.schedule(fn, object, name, 15000 /* 15s max wait */);
}

function startup() {
  GeckoViewUtils.initLogging("XUL", window);

  const browser = createBrowser();
  ModuleManager.init(browser, [
    {
      name: "GeckoViewContent",
      onInit: {
        resource: "resource://gre/modules/GeckoViewContent.sys.mjs",
        actors: {
          GeckoViewContent: {
            parent: {
              esModuleURI: "resource:///actors/GeckoViewContentParent.sys.mjs",
            },
            child: {
              esModuleURI: "resource:///actors/GeckoViewContentChild.sys.mjs",
              events: {
                mozcaretstatechanged: { capture: true, mozSystemGroup: true },
                pageshow: { mozSystemGroup: true },
              },
            },
            allFrames: true,
            messageManagerGroups: ["browsers"],
          },
        },
      },
      onEnable: {
        actors: {
          ContentDelegate: {
            parent: {
              esModuleURI: "resource:///actors/ContentDelegateParent.sys.mjs",
            },
            child: {
              esModuleURI: "resource:///actors/ContentDelegateChild.sys.mjs",
              events: {
                DOMContentLoaded: {},
                DOMMetaViewportFitChanged: {},
                "MozDOMFullscreen:Entered": {},
                "MozDOMFullscreen:Exit": {},
                "MozDOMFullscreen:Exited": {},
                "MozDOMFullscreen:Request": {},
                MozFirstContentfulPaint: {},
                MozPaintStatusReset: {},
                contextmenu: {},
              },
            },
            allFrames: true,
            messageManagerGroups: ["browsers"],
          },
        },
      },
    },
    {
      name: "GeckoViewNavigation",
      onInit: {
        resource: "resource://gre/modules/GeckoViewNavigation.sys.mjs",
      },
    },
    {
      name: "GeckoViewProcessHangMonitor",
      onInit: {
        resource: "resource://gre/modules/GeckoViewProcessHangMonitor.sys.mjs",
      },
    },
    {
      name: "GeckoViewProgress",
      onEnable: {
        resource: "resource://gre/modules/GeckoViewProgress.sys.mjs",
        actors: {
          ProgressDelegate: {
            parent: {
              esModuleURI: "resource:///actors/ProgressDelegateParent.sys.mjs",
            },
            child: {
              esModuleURI: "resource:///actors/ProgressDelegateChild.sys.mjs",
              events: {
                MozAfterPaint: { capture: false, mozSystemGroup: true },
                DOMContentLoaded: { capture: false, mozSystemGroup: true },
                pageshow: { capture: false, mozSystemGroup: true },
              },
            },
            messageManagerGroups: ["browsers"],
          },
        },
      },
    },
    {
      name: "GeckoViewScroll",
      onEnable: {
        actors: {
          ScrollDelegate: {
            parent: {
              esModuleURI: "resource:///actors/ScrollDelegateParent.sys.mjs",
            },
            child: {
              esModuleURI: "resource:///actors/ScrollDelegateChild.sys.mjs",
              events: {
                mozvisualscroll: { mozSystemGroup: true },
              },
            },
            messageManagerGroups: ["browsers"],
          },
        },
      },
    },
    {
      name: "GeckoViewSelectionAction",
      onEnable: {
        resource: "resource://gre/modules/GeckoViewSelectionAction.sys.mjs",
        actors: {
          SelectionActionDelegate: {
            parent: {
              esModuleURI:
                "resource:///actors/SelectionActionDelegateParent.sys.mjs",
            },
            child: {
              esModuleURI:
                "resource:///actors/SelectionActionDelegateChild.sys.mjs",
              events: {
                mozcaretstatechanged: { mozSystemGroup: true },
                pagehide: { capture: true, mozSystemGroup: true },
                deactivate: { mozSystemGroup: true },
              },
            },
            allFrames: true,
            messageManagerGroups: ["browsers"],
          },
        },
      },
    },
    {
      name: "GeckoViewSettings",
      onInit: {
        resource: "resource://gre/modules/GeckoViewSettings.sys.mjs",
        actors: {
          GeckoViewSettings: {
            child: {
              esModuleURI: "resource:///actors/GeckoViewSettingsChild.sys.mjs",
            },
          },
        },
      },
    },
    {
      name: "GeckoViewTab",
      onInit: {
        resource: "resource://gre/modules/GeckoViewTab.sys.mjs",
      },
    },
    {
      name: "GeckoViewContentBlocking",
      onInit: {
        resource: "resource://gre/modules/GeckoViewContentBlocking.sys.mjs",
      },
    },
    {
      name: "SessionStateAggregator",
      onInit: {
        frameScript: "chrome://geckoview/content/SessionStateAggregator.js",
      },
    },
    {
      name: "GeckoViewAutofill",
      onInit: {
        actors: {
          GeckoViewAutoFill: {
            parent: {
              esModuleURI: "resource:///actors/GeckoViewAutoFillParent.sys.mjs",
            },
            child: {
              esModuleURI: "resource:///actors/GeckoViewAutoFillChild.sys.mjs",
              events: {
                DOMFormHasPassword: {
                  mozSystemGroup: true,
                  capture: false,
                },
                DOMInputPasswordAdded: {
                  mozSystemGroup: true,
                  capture: false,
                },
                pagehide: {
                  mozSystemGroup: true,
                  capture: false,
                },
                pageshow: {
                  mozSystemGroup: true,
                  capture: false,
                },
                focusin: {
                  mozSystemGroup: true,
                  capture: false,
                },
                focusout: {
                  mozSystemGroup: true,
                  capture: false,
                },
                "PasswordManager:ShowDoorhanger": {},
              },
            },
            allFrames: true,
            messageManagerGroups: ["browsers"],
          },
        },
      },
    },
    {
      name: "GeckoViewMediaControl",
      onEnable: {
        resource: "resource://gre/modules/GeckoViewMediaControl.sys.mjs",
        actors: {
          MediaControlDelegate: {
            parent: {
              esModuleURI:
                "resource:///actors/MediaControlDelegateParent.sys.mjs",
            },
            child: {
              esModuleURI:
                "resource:///actors/MediaControlDelegateChild.sys.mjs",
              events: {
                "MozDOMFullscreen:Entered": {},
                "MozDOMFullscreen:Exited": {},
              },
            },
            allFrames: true,
            messageManagerGroups: ["browsers"],
          },
        },
      },
    },
    {
      name: "GeckoViewAutocomplete",
      onInit: {
        actors: {
          FormAutofill: {
            parent: {
              esModuleURI: "resource://autofill/FormAutofillParent.sys.mjs",
            },
            child: {
              esModuleURI: "resource://autofill/FormAutofillChild.sys.mjs",
              events: {
                focusin: {},
                "form-submission-detected": {},
              },
            },
            allFrames: true,
            messageManagerGroups: ["browsers"],
          },
        },
      },
    },
    {
      name: "GeckoViewPrompter",
      onInit: {
        actors: {
          GeckoViewPrompter: {
            parent: {
              esModuleURI: "resource:///actors/GeckoViewPrompterParent.sys.mjs",
            },
            child: {
              esModuleURI: "resource:///actors/GeckoViewPrompterChild.sys.mjs",
            },
            allFrames: true,
            includeChrome: true,
          },
        },
      },
    },
    {
      name: "GeckoViewPrintDelegate",
      onInit: {
        actors: {
          GeckoViewPrintDelegate: {
            parent: {
              esModuleURI:
                "resource:///actors/GeckoViewPrintDelegateParent.sys.mjs",
            },
            child: {
              esModuleURI:
                "resource:///actors/GeckoViewPrintDelegateChild.sys.mjs",
            },
            allFrames: true,
          },
        },
      },
    },
    {
      name: "GeckoViewExperimentDelegate",
      onInit: {
        actors: {
          GeckoViewExperimentDelegate: {
            parent: {
              esModuleURI:
                "resource:///actors/GeckoViewExperimentDelegateParent.sys.mjs",
            },
            allFrames: true,
          },
        },
      },
    },
    {
      name: "GeckoViewTranslations",
      onInit: {
        resource: "resource://gre/modules/GeckoViewTranslations.sys.mjs",
      },
    },
  ]);

  if (!Services.appinfo.sessionHistoryInParent) {
    browser.prepareToChangeRemoteness = () =>
      ModuleManager.prepareToChangeRemoteness();
    browser.afterChangeRemoteness = switchId =>
      ModuleManager.afterBrowserRemotenessChange(switchId);
  }

  browser.addEventListener("WillChangeBrowserRemoteness", () =>
    ModuleManager.willChangeBrowserRemoteness()
  );

  browser.addEventListener("DidChangeBrowserRemoteness", () =>
    ModuleManager.didChangeBrowserRemoteness()
  );

  // Allows actors to access ModuleManager.
  window.moduleManager = ModuleManager;

  window.prompts = () => {
    return window.ModuleManager.getActor("GeckoViewPrompter").getPrompts();
  };

  Services.tm.dispatchToMainThread(() => {
    // This should always be the first thing we do here - any additional delayed
    // initialisation tasks should be added between "browser-delayed-startup-finished"
    // and "browser-idle-startup-tasks-finished".

    // Bug 1496684: Various bits of platform stuff depend on this notification
    // to learn when a browser window has finished its initial (chrome)
    // initialisation, especially with regards to the very first window that is
    // created. Therefore, GeckoView "windows" need to send this, too.
    InitLater(() =>
      Services.obs.notifyObservers(window, "browser-delayed-startup-finished")
    );

    // Let the extension code know it can start loading things that were delayed
    // while GeckoView started up.
    InitLater(() => {
      Services.obs.notifyObservers(window, "extensions-late-startup");
    });

    InitLater(() => {
      // TODO bug 1730026: this runs too often. It should run once.
      RemoteSecuritySettings.init();
    });

    InitLater(() => {
      // Initialize safe browsing module. This is required for content
      // blocking features and manages blocklist downloads and updates.
      SafeBrowsing.init();
    });

    InitLater(() => {
      // It's enough to run this once to set up FOG.
      // (See also bug 1730026.)
      Services.fog.registerCustomPings();
    });

    InitLater(() => {
      // Initialize the blocklist module.
      // TODO bug 1730026: this runs too often. It should run once.
      Blocklist.loadBlocklistAsync();
    });

    InitLater(() => {
      // Call the init function for the CaptchaDetectionPingUtils module.
      // This function adds pref observers that flushes the ping. It also
      // submits the ping if it has data and has been about 24 hours since the
      // last submission.
      CaptchaDetectionPingUtils.init();
    });

    // This should always go last, since the idle tasks (except for the ones with
    // timeouts) should execute in order. Note that this observer notification is
    // not guaranteed to fire, since the window could close before we get here.

    // This notification in particular signals the ScriptPreloader that we have
    // finished startup, so it can now stop recording script usage and start
    // updating the startup cache for faster script loading.
    InitLater(() =>
      Services.obs.notifyObservers(
        window,
        "browser-idle-startup-tasks-finished"
      )
    );
  });

  // Move focus to the content window at the end of startup,
  // so things like text selection can work properly.
  browser.focus();

  InitializationTracker.onInitialized(performance.now());
}

Messung V0.5
C=88 H=94 G=90

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge