tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_preferences_usage.js (7676B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 if (SpecialPowers.useRemoteSubframes) {
      5  requestLongerTimeout(2);
      6 }
      7 
      8 const DEFAULT_PROCESS_COUNT = Services.prefs
      9  .getDefaultBranch(null)
     10  .getIntPref("dom.ipc.processCount");
     11 
     12 /**
     13 * A test that checks whether any preference getter from the given list
     14 * of stats was called more often than the max parameter.
     15 *
     16 * @param {Array}  stats - an array of [prefName, accessCount] tuples
     17 * @param {number} max - the maximum number of times any of the prefs should
     18 *                 have been called.
     19 * @param {object} knownProblematicPrefs (optional) - an object that defines
     20 *                 prefs that should be exempt from checking the
     21 *                 maximum access. It looks like the following:
     22 *
     23 *                 pref_name: {
     24 *                   min: [Number] the minimum amount of times this should have
     25 *                                 been called (to avoid keeping around dead items)
     26 *                   max: [Number] the maximum amount of times this should have
     27 *                                 been called (to avoid this creeping up further)
     28 *                 }
     29 */
     30 function checkPrefGetters(stats, max, knownProblematicPrefs = {}) {
     31  let getterStats = Object.entries(stats).sort(
     32    ([, val1], [, val2]) => val2 - val1
     33  );
     34 
     35  // Clone the list to be able to delete entries to check if we
     36  // forgot any later on.
     37  knownProblematicPrefs = Object.assign({}, knownProblematicPrefs);
     38 
     39  for (let [pref, count] of getterStats) {
     40    let prefLimits = knownProblematicPrefs[pref];
     41    if (!prefLimits) {
     42      Assert.lessOrEqual(
     43        count,
     44        max,
     45        `${pref} should not be accessed more than ${max} times.`
     46      );
     47    } else {
     48      // Still record how much this pref was accessed even if we don't do any real assertions.
     49      if (!prefLimits.min && !prefLimits.max) {
     50        info(
     51          `${pref} should not be accessed more than ${max} times and was accessed ${count} times.`
     52        );
     53      }
     54 
     55      if (prefLimits.min) {
     56        Assert.lessOrEqual(
     57          prefLimits.min,
     58          count,
     59          `${pref} should be accessed at least ${prefLimits.min} times.`
     60        );
     61      }
     62      if (prefLimits.max) {
     63        Assert.lessOrEqual(
     64          count,
     65          prefLimits.max,
     66          `${pref} should be accessed at most ${prefLimits.max} times.`
     67        );
     68      }
     69      delete knownProblematicPrefs[pref];
     70    }
     71  }
     72 
     73  let unusedPrefs = Object.keys(knownProblematicPrefs);
     74  is(
     75    unusedPrefs.length,
     76    0,
     77    `Should have accessed all known problematic prefs. Remaining: ${unusedPrefs}`
     78  );
     79 }
     80 
     81 /**
     82 * A helper function to read preference access data
     83 * using the Services.prefs.readStats() function.
     84 */
     85 function getPreferenceStats() {
     86  let stats = {};
     87  Services.prefs.readStats((key, value) => (stats[key] = value));
     88  return stats;
     89 }
     90 
     91 add_task(async function debug_only() {
     92  ok(AppConstants.DEBUG, "You need to run this test on a debug build.");
     93 });
     94 
     95 // Just checks how many prefs were accessed during startup.
     96 add_task(async function startup() {
     97  let max = 40;
     98 
     99  let knownProblematicPrefs = {
    100    "network.loadinfo.skip_type_assertion": {
    101      // This is accessed in debug only.
    102    },
    103  };
    104 
    105  let startupRecorder =
    106    Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
    107  await startupRecorder.done;
    108 
    109  ok(startupRecorder.data.prefStats, "startupRecorder has prefStats");
    110 
    111  checkPrefGetters(startupRecorder.data.prefStats, max, knownProblematicPrefs);
    112 });
    113 
    114 // This opens 10 tabs and checks pref getters.
    115 add_task(async function open_10_tabs() {
    116  // This is somewhat arbitrary. When we had a default of 4 content processes
    117  // the value was 15. We need to scale it as we increase the number of
    118  // content processes so we approximate with 4 * process_count.
    119  const max = 4 * DEFAULT_PROCESS_COUNT;
    120 
    121  let knownProblematicPrefs = {
    122    "browser.tabs.remote.logSwitchTiming": {
    123      max: 35,
    124    },
    125    "network.loadinfo.skip_type_assertion": {
    126      // This is accessed in debug only.
    127    },
    128  };
    129 
    130  Services.prefs.resetStats();
    131 
    132  let tabs = [];
    133  while (tabs.length < 10) {
    134    tabs.push(
    135      await BrowserTestUtils.openNewForegroundTab(
    136        gBrowser,
    137        // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    138        "http://example.com",
    139        true,
    140        true
    141      )
    142    );
    143  }
    144 
    145  for (let tab of tabs) {
    146    await BrowserTestUtils.removeTab(tab);
    147  }
    148 
    149  checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs);
    150 });
    151 
    152 // This navigates to 50 sites and checks pref getters.
    153 add_task(async function navigate_around() {
    154  await SpecialPowers.pushPrefEnv({
    155    set: [
    156      // Disable bfcache so that we can measure more accurately the number of
    157      // pref accesses in the child processes.
    158      // If bfcache is enabled on Fission
    159      // security.sandbox.content.force-namespace is accessed only a couple of
    160      // times.
    161      ["browser.sessionhistory.max_total_viewers", 0],
    162    ],
    163  });
    164 
    165  let max = 40;
    166 
    167  let knownProblematicPrefs = {
    168    "network.loadinfo.skip_type_assertion": {
    169      // This is accessed in debug only.
    170    },
    171  };
    172 
    173  if (SpecialPowers.useRemoteSubframes) {
    174    // We access this when considering starting a new content process.
    175    // Because there is no complete list of content process types,
    176    // caching this is not trivial. Opening 50 different content
    177    // processes and throwing them away immediately is a bit artificial;
    178    // we're more likely to keep some around so this shouldn't be quite
    179    // this bad in practice. Fixing this is
    180    // https://bugzilla.mozilla.org/show_bug.cgi?id=1600266
    181    knownProblematicPrefs["dom.ipc.processCount.webIsolated"] = {
    182      min: 50,
    183      max: 51,
    184    };
    185    if (AppConstants.platform == "linux") {
    186      // The following sandbox pref is covered by
    187      // https://bugzilla.mozilla.org/show_bug.cgi?id=1600189
    188      knownProblematicPrefs["security.sandbox.content.force-namespace"] = {
    189        min: 45,
    190        max: 55,
    191      };
    192    } else if (AppConstants.platform == "win") {
    193      // The following 2 graphics prefs are covered by
    194      // https://bugzilla.mozilla.org/show_bug.cgi?id=1639497
    195      knownProblematicPrefs["gfx.canvas.azure.backends"] = {
    196        min: 90,
    197        max: 110,
    198      };
    199      knownProblematicPrefs["gfx.content.azure.backends"] = {
    200        min: 90,
    201        max: 110,
    202      };
    203      // The following 2 sandbox prefs are covered by
    204      // https://bugzilla.mozilla.org/show_bug.cgi?id=1639494
    205      knownProblematicPrefs["security.sandbox.content.read_path_whitelist"] = {
    206        min: 47,
    207        max: 55,
    208      };
    209      knownProblematicPrefs["security.sandbox.logging.enabled"] = {
    210        min: 47,
    211        max: 55,
    212      };
    213    }
    214  }
    215 
    216  Services.prefs.resetStats();
    217 
    218  let tab = await BrowserTestUtils.openNewForegroundTab(
    219    gBrowser,
    220    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    221    "http://example.com",
    222    true,
    223    true
    224  );
    225 
    226  let urls = [
    227    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    228    "http://example.com/",
    229    "https://example.com/",
    230    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    231    "http://example.org/",
    232    "https://example.org/",
    233  ];
    234 
    235  for (let i = 0; i < 50; i++) {
    236    let url = urls[i % urls.length];
    237    info(`Navigating to ${url}...`);
    238    BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url);
    239    await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url);
    240    info(`Loaded ${url}.`);
    241  }
    242 
    243  await BrowserTestUtils.removeTab(tab);
    244 
    245  checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs);
    246 });