Debugging

This page is intended to help developers figure out problems that they can reproduce locally or to test changes.

Determining the Update URL Being Used

When updates aren’t returning what we expect, it can be valuable to make sure that we are using the expected update URL. This can be a bit trickier than expected since there are multiple things that influence it. Checking it from the wrong place could result in an incorrect value being given. The correct command is:

const checker = Cc["@mozilla.org/updates/update-checker;1"].getService(Ci.nsIUpdateChecker);
await checker.wrappedJSObject.getUpdateURL(checker.BACKGROUND_CHECK);

Kicking Off a Background Update

Sometimes, in testing, we may want to initiate an update as if it was launched by Firefox checking in the background rather than checking using an update UI. This can be done with this command:

Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsITimerCallback).notify(null);

Debugging the Update Binary in an Automated Test

Sometimes it can be a real struggle to figure out why the update binary is acting unexpectedly in testing. And attaching a debugger to something that runs so briefly can be difficult. In this situation, you can add these lines here:

  let debuggerPath =
    "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\Common7\\IDE\\devenv.exe";

  args.unshift(launchBin.path);
  args.unshift("/DebugExe");
  launchBin = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
  launchBin.initWithPath(debuggerPath);

Running Update for a Local Build

Note: This has not been updated since the addition of ./mach update serve in Bug 1655128. It could probably be simplified by using that.

See the main documentation for this, here.

This script is meant to automate this process but is currently not designed to be very portable and thus will require some setup:

  • The build directory should use a mozconfig file including ac_add_options --enable-unverified-updates and should specify the object directory using mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/<insert dir name here>. Note that a full rebuild will be necessary after changing these values.

  • Make a directory to serve updates from (referred to later as fake_update_directory). Open a terminal instance running python3 -m http.server 8000 in that directory.

  • You will need an application or script that can calculate sha512 hashes. The example script below uses this one.

  • The 3 variables at the top of this script will also need to be set properly. The update directory can most easily be found by just running Firefox from the directory it will be installed into and checking about:support. Ideally, this script would calculate the update directory itself, but it seems quite a bit harder to calculate a City Hash (or find another tool that can) than to just have Firefox calculate the update directory for you.

It is expected that this script will be run from the root of the build directory.

#!/bin/bash
set -e

# fake_update_directory is where the XML and MAR will be written
fake_update_directory="${HOME}/proj/fake_updater"
install_parent_dir="${HOME}/local_install"
# The contents of update_directory will be deleted when this script runs to
# prevent an old update from being installed
update_dir="/c/ProgramData/Mozilla-1de4eec8-1241-4177-a864-e594e8d1fb38/updates/D08B6C7768F21D1D"


mar_template=$(cat <<'END_HEREDOC'
<?xml version="1.0" encoding="UTF-8"?>
<updates>
    <update type="minor" displayVersion="2000.0a1" appVersion="2000.0a1" platformVersion="2000.0a1" buildID="21181002100236">
        <patch type="complete" URL="http://127.0.0.1:8000/local_update.mar" hashFunction="sha512" hashValue="%HASH_VALUE%" size="%SIZE%"/>
    </update>
</updates>
END_HEREDOC
)

policy_contents=$(cat <<'END_HEREDOC'
{
  "policies": {
    "AppUpdateURL": "http://127.0.0.1:8000/update.xml"
  }
}
END_HEREDOC
)


if [[ ! -f "mach" ]] || [[ ! -f "mozconfig" ]] ; then
  echo "This doesn't look like mozilla-central"
  exit -1
fi

obj_dir="$(grep '^mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/' mozconfig | sed 's|^mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/||')"

if [[ $(echo "$obj_dir" | wc -l) -gt 1 ]] || [[ -z "$obj_dir" ]]; then
  echo "Unable to determine object directory"
  exit -1
fi
echo "Determined object directory to be \"${obj_dir}\""
if [[ ! -d "$obj_dir" ]]; then
  echo "Object directory doesn't exist"
  exit -1
fi

echo "Building..."
MOZ_NOSPAM="true" ./mach build &> /dev/null
echo "Packaging..."
MOZ_NOSPAM="true" ./mach package &> /dev/null
echo "Creating MAR at \"${fake_update_directory}/local_update.mar\"..."
touch "${obj_dir}/dist/firefox/precomplete"
MAR="${obj_dir}/dist/host/bin/mar.exe" MOZ_PRODUCT_VERSION="2000.0a1" MAR_CHANNEL_ID="default" ./tools/update-packaging/make_full_update.sh "${fake_update_directory}/local_update.mar" "${obj_dir}/dist/firefox" &> /dev/null

# Make the installation
echo "Installing Firefox to \"${install_parent_dir}/firefox\"..."
rm -rf "${install_parent_dir}/firefox" &> /dev/null
cp -r "${obj_dir}/dist/firefox" "$install_parent_dir" &> /dev/null

# Add the update URL policy
echo "Adding the update URL policy..."
mkdir "${install_parent_dir}/firefox/distribution"
echo "$policy_contents" > "${install_parent_dir}/firefox/distribution/policies.json"

# Clear out the update directory
if [[ -z "$update_dir" ]]; then
  echo "Configuration error. It doesn't look like the update directory is defined"
  exit -1
fi
update_config_path="${update_dir}/update-config.json"
update_config_contents=
if [[ -f "${update_config_path}" ]]; then
  echo "Saving update config from the update directory"
  update_config_contents="$(cat "${update_config_path}")"
fi
echo "Clearing out the update files in \"${update_dir}\""
rm -rf "${update_dir}"/* &> /dev/null
if [[ -n "$update_config_contents" ]]; then
  echo "Restoring update config"
  echo "${update_config_contents}" > "${update_config_path}"
fi

# Write out the update XML
echo "Writing update XML to \"${fake_update_directory}/update.xml\"..."
size="$($(which ls) -l "${fake_update_directory}/local_update.mar" | cut -d " " -f5)"
hash="$(digest sha512 -q "${fake_update_directory}/local_update.mar")"
mar_contents="$(echo "$mar_template" | sed "s|%HASH_VALUE%|${hash}|g;s|%SIZE%|${size}|g")"
echo "$mar_contents" > "${fake_update_directory}/update.xml"

echo
echo "Done."

This sets Firefox up to run through the update process such that it is updated to run the same thing that was already running. This allows multiple passes of testing without having to reinstall. When changes are made, run the script again before testing further.