blob: 4466a72f1f7ff922de4da876fdc99d93da4cfe8d [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package firmware
import (
"context"
"os"
"path"
"path/filepath"
"strings"
"time"
empty "github.com/golang/protobuf/ptypes/empty"
fp "go.chromium.org/tast-tests/cros/common/fingerprint"
"go.chromium.org/tast-tests/cros/common/tbdep"
"go.chromium.org/tast-tests/cros/remote/dutfs"
"go.chromium.org/tast-tests/cros/remote/firmware/fingerprint"
"go.chromium.org/tast-tests/cros/remote/firmware/fingerprint/rpcdut"
"go.chromium.org/tast-tests/cros/services/cros/firmware"
"go.chromium.org/tast/core/ctxutil"
"go.chromium.org/tast/core/errors"
"go.chromium.org/tast/core/ssh/linuxssh"
"go.chromium.org/tast/core/testing"
"go.chromium.org/tast/core/testing/hwdep"
)
const (
latestLog = "/var/log/biod/bio_fw_updater.LATEST"
previousLog = "/var/log/biod/bio_fw_updater.PREVIOUS"
successString = "The update was successful."
)
func init() {
testing.AddTest(&testing.Test{
Func: FpUpdater,
Desc: "Checks that the fingerprint firmware updater succeeds when an update is needed",
Contacts: []string{
"chromeos-fingerprint@google.com",
"tomhughes@chromium.org",
},
// ChromeOS > Platform > Services > Fingerprint
BugComponent: "b:782045",
Attr: []string{"group:fingerprint-cq", "group:fingerprint-release"},
Timeout: 9 * time.Minute,
SoftwareDeps: []string{"biometrics_daemon"},
HardwareDeps: hwdep.D(hwdep.Fingerprint()),
ServiceDeps: []string{"tast.cros.firmware.FpUpdaterService", "tast.cros.platform.UpstartService", dutfs.ServiceName},
TestBedDeps: []string{tbdep.Fingerprint, tbdep.ServoStateWorking},
Vars: []string{"servo"},
Data: []string{"nocturne_fp_v2.0.3266-99b5e2c98_20201214.bin",
"nami_fp_v2.0.3266-99b5e2c98_20201214.bin",
"bloonchipper_v2.0.14206-ad46faf_20220718.bin",
"buccaneer_v2.0.26327-becca858dd_20240922.bin",
"dartmonkey_v2.0.2887-311310808_20201214.bin",
"helipilot_v2.0.24290-9ec5208ff7_20240321.bin"},
LacrosStatus: testing.LacrosVariantUnneeded,
})
}
// getOldFirmwarePath returns the path to a known out-dated firmware.
func getOldFirmwarePath(s *testing.State, fpBoard fp.BoardName) (string, error) {
switch fpBoard {
case fp.BoardNameNocturne:
return s.DataPath("nocturne_fp_v2.0.3266-99b5e2c98_20201214.bin"), nil
case fp.BoardNameNami:
return s.DataPath("nami_fp_v2.0.3266-99b5e2c98_20201214.bin"), nil
case fp.BoardNameBloonchipper:
return s.DataPath("bloonchipper_v2.0.14206-ad46faf_20220718.bin"), nil
case fp.BoardNameBuccaneer:
return s.DataPath("buccaneer_v2.0.26327-becca858dd_20240922.bin"), nil
case fp.BoardNameDartmonkey:
return s.DataPath("dartmonkey_v2.0.2887-311310808_20201214.bin"), nil
case fp.BoardNameHelipilot:
return s.DataPath("helipilot_v2.0.24290-9ec5208ff7_20240321.bin"), nil
default:
return "", errors.Errorf("no old firmware for %q", fpBoard)
}
}
// flashOldRWFirmware flashes a known out-dated version of firmware.
func flashOldRWFirmware(ctx context.Context, s *testing.State, d *rpcdut.RPCDUT) error {
fpBoard, err := fingerprint.Board(ctx, d)
if err != nil {
return errors.Wrap(err, "failed to get fp board")
}
testing.ContextLogf(ctx, "fp board name: %q", fpBoard)
oldFirmwarePath, err := getOldFirmwarePath(s, fpBoard)
if err != nil {
return errors.Wrap(err, "failed to get old firmware path")
}
oldFirmwarePathOnDut := filepath.Join("/tmp", path.Base(oldFirmwarePath))
if _, err := linuxssh.PutFiles(
ctx, d.Conn(), map[string]string{oldFirmwarePath: oldFirmwarePathOnDut},
linuxssh.DereferenceSymlinks); err != nil {
return errors.Wrap(err, "failed to send old firmware to DUT")
}
if err := fingerprint.FlashFirmwareUpdate(ctx, d, fingerprint.ImageTypeRW, oldFirmwarePathOnDut); err != nil {
return errors.Wrap(err, "failed to flash RW firmware")
}
// Check if FPMCU is running flashed RW.
buildRWVersion, err := fingerprint.GetBuildRWFirmwareVersion(ctx, d, oldFirmwarePathOnDut)
if err != nil {
return errors.Wrap(err, "failed to query build RW version")
}
runningRWVersion, err := fingerprint.RunningRWVersion(ctx, d)
if err != nil {
return errors.Wrap(err, "failed to query running RW version")
}
if runningRWVersion != buildRWVersion {
return errors.Errorf("FPMCU is running incorrect RW version. Running %s, want %s", runningRWVersion, buildRWVersion)
}
return nil
}
func FpUpdater(ctx context.Context, s *testing.State) {
d, err := rpcdut.NewRPCDUT(ctx, s.DUT(), s.RPCHint())
if err != nil {
s.Fatal("Failed to connect RPCDUT: ", err)
}
defer d.Close(ctx)
servoSpec, ok := s.Var("servo")
if !ok {
servoSpec = ""
}
// Set SW write protect to true to enable RDP1 and HW write protect to true.
firmwareFile, err := fingerprint.NewMPFirmwareFile(ctx, d)
if err != nil {
s.Fatal("Failed to create MP firmwareFile: ", err)
}
t, err := fingerprint.NewFirmwareTest(ctx, d, servoSpec, s.OutDir(), firmwareFile, true /*HW protect*/, true /*SW protect*/)
if err != nil {
s.Fatal("Failed to create new firmware test: ", err)
}
cleanupCtx := ctx
defer func() {
if err := t.Close(cleanupCtx); err != nil {
s.Fatal("Failed to clean up: ", err)
}
}()
ctx, cancel := ctxutil.Shorten(ctx, t.CleanupTime())
defer cancel()
// If FP updater disabled, enable it.
fpUpdaterEnabled, err := fingerprint.IsFPUpdaterEnabled(ctx, d)
if err != nil {
s.Fatal("Failed to check FP updater state: ", err)
}
if !fpUpdaterEnabled {
if err := fingerprint.EnableFPUpdater(ctx, d); err != nil {
s.Fatal("Failed to enable FP updater: ", err)
}
}
testing.ContextLog(ctx, "Flashing outdated FP firmware")
if err := flashOldRWFirmware(ctx, s, d); err != nil {
s.Fatal("Failed to flash outdated RW firmware: ", err)
}
testing.ContextLog(ctx, "Invoking fp updater")
if err := d.Conn().CommandContext(ctx, "bio_fw_updater").Run(); err != nil {
s.Fatal("Failed to execute bio_fw_updater: ", err)
}
fpUpdaterService := firmware.NewFpUpdaterServiceClient(d.RPC().Conn)
response, err := fpUpdaterService.ReadUpdaterLogs(ctx, &empty.Empty{})
if err != nil {
s.Fatal("Failed to read updater logs: ", err)
}
latest := response.GetLatestLog()
previous := response.GetPreviousLog()
latestLogFile, err := os.Create(filepath.Join(s.OutDir(), path.Base(latestLog)))
if err != nil {
s.Error("Failed to write latest updater log to file: ", err)
}
defer latestLogFile.Close()
if _, err := latestLogFile.WriteString(latest); err != nil {
s.Error("Failed to write latest updater log to file: ", err)
}
previousLogFile, err := os.Create(filepath.Join(s.OutDir(), path.Base(previousLog)))
if err != nil {
s.Error("Failed to write previous updater log to file: ", err)
}
defer previousLogFile.Close()
if _, err := previousLogFile.WriteString(previous); err != nil {
s.Error("Failed to write previous updater log to file: ", err)
}
if !strings.Contains(latest, successString) {
s.Fatal("Updater did not succeed, please check output dir")
}
buildRWVersion, err := fingerprint.GetBuildRWFirmwareVersion(ctx, d, t.FirmwareFile().FilePath)
if err != nil {
s.Fatal("Failed to query build RW version: ", err)
}
runningRWVersion, err := fingerprint.RunningRWVersion(ctx, d)
if err != nil {
s.Fatal("Failed to query running RW version: ", err)
}
if runningRWVersion != buildRWVersion {
s.Fatalf("Running RW version %s, want %s", runningRWVersion, buildRWVersion)
}
}