sys-apps/fwupd: Trigger fwupdtool update on boot

Adds a new script to be run by /etc/init/boot-update-firmware.conf to
install any pending firmware updates available in the system.

BUG=b:167681094
TEST=emerge-sarien fwupd; reboot with a pending update

Cq-Depend: chromium:2405305
Change-Id: I05a9bc6521bd6d4f7de79f85420edd71a3e34167
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/2391971
Reviewed-by: Benson Leung <bleung@google.com>
Tested-by: Daniel Campello <campello@chromium.org>
Commit-Queue: Daniel Campello <campello@chromium.org>
Auto-Submit: Daniel Campello <campello@chromium.org>
diff --git a/sys-apps/fwupd/files/fwupd-at-boot.sh b/sys-apps/fwupd/files/fwupd-at-boot.sh
new file mode 100755
index 0000000..89b3572
--- /dev/null
+++ b/sys-apps/fwupd/files/fwupd-at-boot.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2020 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# We block the UI at splash screen to check for available firmware
+# updates and apply them. This script is called by `pre-ui` upstart job.
+
+LOGGER_TAG="fwupd-at-boot"
+
+main() {
+  local ret=0
+
+  if [ "$#" -ne 0 ]; then
+	logger -t "${LOGGER_TAG}" "Too many arguments."
+	return 1
+  fi
+
+  local pending
+  pending="$(find /var/lib/fwupd/pending -type f -size -100c 2>/dev/null)"
+  if [ -z "${pending[*]}" ]; then
+	return "${ret}"
+  fi
+
+  # Background process that shows boot alert.
+  chromeos-boot-alert update_fwupd_firmware &
+  local bg_pid=$!
+
+  # Give it a second for USB enumeration to detect devices.
+  sleep 1
+
+  local i
+  for i in "${pending[@]}"; do
+    # Trigger fwupdtool-update job, which blocks until the job completes.
+    /sbin/initctl emit fwupdtool-update GUID="${i##*/}" \
+      PLUGIN="$(cat "${i}")" AT_BOOT="true" || ret=1
+    rm "${i}"
+  done
+
+  # Kill the chromeos-boot-alert in the background process.
+  kill -9 "${bg_pid}"
+
+  return "${ret}"
+}
+
+main "$@"
diff --git a/sys-apps/fwupd/files/fwupdtool-update.conf b/sys-apps/fwupd/files/fwupdtool-update.conf
index fbead59..3bdf960 100644
--- a/sys-apps/fwupd/files/fwupdtool-update.conf
+++ b/sys-apps/fwupd/files/fwupdtool-update.conf
@@ -15,7 +15,11 @@
 import GUID
 # FWUPD plugin to be used by fwupdtool update invokation.
 import PLUGIN
+# Are we running at boot time.
+import AT_BOOT
 
+env AT_BOOT="false"
+env FILTER="usable-during-update"
 env REGEX="^[0-9a-f]\{8\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{12\}$"
 env MINIJAIL_ARGS="--uts -e -l -p -N \
     -v -P /mnt/empty -b / -b /proc -r -t -b /dev,,1 -k run,/run,tmpfs \
@@ -28,8 +32,8 @@
     logger -p err -t "${UPSTART_JOB}" "Invalid GUID: ${GUID}"
     exit 1
   fi
-  mkdir -p /var/cache/fwupd /var/lib/fwupd
-  chown -R fwupd:fwupd /var/cache/fwupd /var/lib/fwupd
+  mkdir -p /var/cache/fwupd /var/lib/fwupd /var/lib/fwupd/pending/
+  chown -R fwupd:fwupd /var/cache/fwupd /var/lib/fwupd /var/lib/fwupd/pending/
   for plugin in ${PLUGIN}; do
     if ! minijail0 ${MINIJAIL_ARGS} -- /usr/bin/fwupdtool get-plugins \
       | grep -x -F "${plugin}:"; then
@@ -61,6 +65,20 @@
     esac
     PLUGIN_ARGS="${PLUGIN_ARGS} --plugins=${plugin}"
   done
-  exec minijail0 ${MINIJAIL_ARGS} -- /usr/bin/fwupdtool update "${GUID}" \
-    ${PLUGIN_ARGS} 2>&1 | logger -t "${UPSTART_JOB}"
+
+  # Apply all updates at boot time since is the safest time to do so.
+  if [ "${AT_BOOT}" = "true" ]; then
+    FILTER=
+  fi
+
+  minijail0 ${MINIJAIL_ARGS} -- /usr/bin/fwupdtool update "${GUID}" \
+    ${PLUGIN_ARGS} --filter="${FILTER}" 2>&1 | logger -t "${UPSTART_JOB}"
+
+  # If there is a pending update we will delay until next boot.
+  if [ "${AT_BOOT}" = "false" ]; then
+    if minijail0 ${MINIJAIL_ARGS} \
+         -- /usr/bin/fwupdtool get-updates "${GUID}" ${PLUGIN_ARGS}; then
+      echo "${PLUGIN}" > /var/lib/fwupd/pending/"${GUID}"
+    fi
+  fi
 end script
diff --git a/sys-apps/fwupd/fwupd-9999.ebuild b/sys-apps/fwupd/fwupd-9999.ebuild
index b63df34..da5fe00 100644
--- a/sys-apps/fwupd/fwupd-9999.ebuild
+++ b/sys-apps/fwupd/fwupd-9999.ebuild
@@ -157,6 +157,9 @@
 	# Install upstart script for automatic firmware update on device plug-in.
 	doins "${FILESDIR}"/fwupdtool-update.conf
 
+	exeinto /usr/share/cros/init
+	doexe "${FILESDIR}"/fwupd-at-boot.sh
+
 	if ! use minimal ; then
 		sed "s@%SEAT_MANAGER%@$(usex elogind elogind consolekit)@" \
 			"${FILESDIR}"/${PN}-r1 \