Code Monkey home page Code Monkey logo

firmware-manager's Introduction

Firmware Manager

One of the remaining issues with firmware management on Linux is the lack of options for graphical frontends to firmware management services like fwupd and system76-firmware. For fwupd, the only solutions available were to distribute either GNOME Software, or KDE Discover; which is not viable for Linux distributions which have their own application centers, or frontends to package managers. For system76-firmware, an official GTK application exists, but it only supports updating System76 firmware, when it would be more ideal if it could support updating firmware from both services.

fwupd is a system service which connects to LVFS to check for firmware updates to a wide variety of hardware from multiple vendors. system76-firmware is our own system service which connects to System76 to check for firmware updates for System76 hardware.

Privacy

To increase privacy, we have disabled telemetry reporting in fwupd on Pop!_OS.

To solve this problem, we've been working on the Firmware Manager project, which we will be shipping to all Pop!_OS users, and System76 hardware customers on any other distribution. It supports checking and updating firmware from the fwupd and system76-firmware services, is Wayland-compatible, and provides both a GTK application and library.

Wayland disallows applications from being run as root, so applications must either call pkexec to prompt the user for permission to run a background process that is root, or connect to an existing background service provided the needed capabilities.

In Pop!_OS, the firmware manager will be integrated into GNOME Settings in a new Firmware panel under the Devices category with the GTK widget library. For other Linux distributions, and for those who do not use GNOME, the GTK application is available to provide the firmware manager widget as a standalone application in its own application window.

Although we've created a GTK application and widget library for our use in Pop!_OS, the core framework is toolkit-agnostic, thereby enabling firmware manager frontends to be written in any toolkit. However, it should be noted that since the framework is written in Rust, frontends would need to use Rust in order to interact with it.

GTK Application

Ubuntu, and other Linux distributions which would prefer to have a standalone desktop application, are free to use the included GTK application.

Screenshot of GTK Application

GNOME Settings Integration

Pop!_OS will be integrating a patch into GNOME Settings which embeds the GTK widget into a new Firmware panel in the Devices category section.

Screenshot of GNOME Settings Integration

Distributing Firmware Manager

When packaging the firmware manager with the GTK frontend, the only dependencies required are libdbus, libgtk, libssl, and libudev. The firmware manager uses DBus to communicate with the system76-firmware and fwupd daemons. Both of which are optional and do not need to be installed in order to use or compile the project. The firmware manager has an initial check for the existence of either daemon. If no daemon is installed, no firmware will be found. If one daemon is installed, then it will discover firmware managed by that service, if managed firmware is found on the system.

As it is written in Rust, Rustc and its Cargo counterpart are required to compile the project. The rust-toolchain file in the root directory of the source repository defines the minimum-supported version of the compiler. We will always depend on a version of Rust that is packaged in the most recent LTS of Ubuntu. You can check what Ubuntu supports here.

To package the project so that it can be built offline in a schroot, there is a make vendor rule which uses the official cargo-vendor utility to fetch all crate dependencies locally, and then generates a tarball which can be distributed in or alongside your source packages. You can then instruct the makefile to build the project with the vendored dependencies by setting VENDOR=1, like so: make VENDOR=1 prefix=/usr.

If your version of Cargo does not have the cargo-vendor feature, you can install cargo-vendor separately here.

For any unfamiliar with Rust, crates are modules of source code with specific functionality that can be massively distributed through public registries like Crates.io, or fetched directly by URL. They are statically-linked when used in a project which builds a library or binary. For applications, Cargo generates a Cargo.lock file which specifies the exact version of every crate that is depended on, and their SHA256 sums. This is to ensure that anyone pulling the project will have the same versions for crate dependencies as used by upstream.

Implementation Details

Like all of our projects today, it is written in Rust, and adheres to current best practices. The project is configured as a workspace, with the core crate providing a generic library for discovering and managing firmware from multiple firmware services. Both fwupd and system76-firmware are supported.

The core is used as the foundation for the two members of this workspace: a notification binary to provide desktop notifications about firmware updates; and a GTK project which serves as both a widget library and desktop application.

Visualization of project structure

* firmware-manager
    * firmware-manager-notify
    * firmware-manager-gtk
        * firmware-manager-gtk-ffi

Core Library

The firmware-manager library provides functions for scanning firmware, and an event loop which receives and sends event signals through channels. One channel receives messages from the frontend, whereas the other sends messages to the frontend. This is designed to be run in a background thread in order to prevent a UI that uses the firmware manager from blocking as requests are being processed.

Additionally, the event API is expected to be used with the provided slotmap-based entity-component architecture. This allows a frontend to assign entity IDs to their requests, and receive those entity IDs back in responses. In doing so, frontends can avoid the need for complex runtime reference-counting, or creating reference cycles. The frontend has exclusive ownership of the data that an entity ID refers to.

GTK Application / Library

The firmware-manager-gtk member of the project provides the firmware widget as a library, and an application which places that widget into a window. This member contains a C FFI sub-member, which builds a dynamic library with a C API and header, and can be used to integrate the widget into any GTK application written in C.

This implementation takes full advantage of the slotmap EC, assigning its own component storages to keep track of state relative to a device entity, such as the widgets assigned to an entity, and information about their firmware.

The included GTK application statically-links the Rust widget library into the binary.

Notification Binary

The firmware-manager-notify member comes with a systemd user timer so that it is executed at login, and then periodically run again at set intervals to check for updates again. When updates are found, a clickable notification will be displayed, which will either open the Firmware panel in GNOME Settings, or the standalone desktop application, depending on which is available on the system.

Supporting Other Frontends

Although the project will release with only a GTK frontend, it is possible for anyone to use it as the foundations for developing a frontend written in any other graphical toolkit. All functionality in the core library is GUI-agnostic, and the entity-component architecture can be extended to their specialized needs. If you write a frontend for another toolkit and want it included in the project, feel free to submit a pull request!

How to Implement Frontend Support

Frontends are expected to store information about devices in the included entity-component architecture in the firmware-manager. Events sent to firmware manager's event loop requires the entity IDs to be sent along with messages. This makes it easier to keep cyclic references out of widget signals, and to identify which firmware a response is referring to. Widgets belonging to a specific firmware device need only send a message through their sender with their attached entity ID.

Build Instructions

This project uses a Makefile. When building the application, the prefix flag must be provided, so that the desktop entry file is generated to point to the correct path of the target binary after installation.

make prefix=/usr
sudo make install prefix=/usr

Note that the generated desktop entry is stored in the target directory, where the pkgconfig file is also stored after it is generated. If you need to regenerate the desktop entry with a different prefix, you can manually call the desktop rule.

make desktop prefix=/usr

Debug Binaries

To build a debug binary, pass DEBUG=1 into make.

make prefix=/usr DEBUG=1
sudo make install DEBUG=1

Vendoring

To vendor the project for packaging, call make vendor. To build a project that has been vendored, pass VENDOR=1 to the makefile.

make vendor
make prefix=/usr VENDOR=1

API Overview

This section provides details about the API and how to call it from Rust or C.

Rust API

The primary API, which the C API is based upon. An example of the Rust API in practice in a GTK application can be found here.

use firmware_manager_gtk::FirmwareWidget;

// Create a new firmware widget
//
// This spawns a background thread which listens for widget events until
// the `Quit` signal is received, which occurs when the firmware widget
// is dropped.
let mut firmware = FirmwareWidget::new();

// Signal the widget's background thread to begin scanning for firmware.
firmware.scan();

// Get the GTK widget from the firmware widget to add into a window.
let widget = firmware.container();

C API

The Rust library also supports C interface with FFI rules in the Makefile for generating a dynamic C library with pkg-config support. This is integrated in GNOME Settings on Pop!_OS.

make ffi prefix=/usr
sudo make install-ffi prefix=/usr

Which can then be imported into a C code base with:

#include <s76_firmware.h>

// Create a new firmware widget
S76FirmwareWidget *firmware =
    s76_firmware_widget_new ();

// Signal the widget's background thread to begin scanning for firmware.
s76_firmware_widget_scan (firmware);

// Get the GTK widget from the firmware widget to attach it to a container.
GtkWidget *firmware_widget =
    s76_firmware_widget_container (firmware);

// Destroy the widget and signal its background thread to quit.
s76_firmware_widget_destroy (firmware);

The C implementation of the Rust application is here, demonstrated with the Meson build system.

firmware-manager's People

Contributors

1280px avatar aanzel avatar agnath18k avatar ahoneybun avatar bittin avatar coffandro avatar crawfxrd avatar evacks avatar francarotti avatar gesteves91 avatar hedw1gp avatar ids1024 avatar jackpot51 avatar jacobgkau avatar leviport avatar matilde-t avatar mmstick avatar n3m0-22 avatar nokyan avatar sigseg5 avatar toomoch avatar verdayne avatar watchmkr avatar ydhnwb avatar yorimirus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

firmware-manager's Issues

Add releases

Please consider adding release tags to this project. Now that it is a dependency of system76-driver, it would be helpful to package maintainers to have versioned releases.

Missing visual indication of changelog content

Currently there is no indication that selecting a device will show the firmware changelog. Using a dropdown button similar to the one on the Color tab would probably be a good fix. The current thought is that such a button should be on the far left of each device.

Plugged in Logitech Mouse and firmware was not detected

Upon plugging in a Logitech MX Master Mouse the fwupd service showed the following logs:

Aug 02 07:14:16 pop-os systemd[1]: Starting Firmware update daemon...
Aug 02 07:14:16 pop-os fwupd[1035]: 13:14:16:0816 FuPluginUefi         failed to add /sys/firmware/efi/esrt/entries/entry0: ESRT GUID '00000000-0000-0000-0000-000000000000' was not valid

The mouse should be detected and shown as it is a valid fwupd device. This error appeared on both the Darter Pro and thelio-major-b2.

Plugging/Unplugging USB devices doesn't refresh the UI

I've found that this project doesn't seem to be listening for events related to a USB or Udev device hotplug. If I unplug a device while running firmware-manager-gtk the device continues to be listed. Likewise if I plug in a device while running it doesn't show up.

Replace pop-up window with dropdown

Firmware changelogs are currently available in a pop-up when the specific device/system is selected. That should be replaced with a dropdown providing this information.

System firmware should still also have a pop-up as the user should confirm this "destructive" action (rebooting and installing system firmware).

Minimum version of Rust required to build?

Looking at README.md, I see no mention of what the minimum version of Rust is required to build Firmware Manager.

I just tried building it on CentOS 7 (after a "yum install cargo") and cargo threw out an error:

cargo run -p tools --bin desktop-entry --
--appid com.system76.FirmwareManager
--name "Firmware Manager"
--icon firmware-manager
--comment "Manage system and device firmware"
--keywords firmware
--keywords system76
--keywords fwupd
--keywords lvfs
--categories System
--categories GTK
--binary com.system76.FirmwareManager
--prefix /usr
--startup-notify
error: failed to parse manifest at /tmp/firmware-manager-master/gtk/Cargo.toml

Caused by:
could not parse input as TOML

Caused by:
unexpected character found: \\ at line 22

EPEL for CentOS 7 only has Rust 1.36.0, which presumably isn't recent enough - could you please add the minimum Rust version requirement to README.md?

On unsupported hardware, application remains blank

ISSUE:
Looking at the firmware tab in GNOME Control Center on 19.04 on a machine without any supported System76 or fwupd supported devices the firmware panel remains blank.

Screenshot from 2019-08-15 22-16-05

HYPOTHESIS: It appears that the search for fwupd devices begins, as evident by the scanning fwupd devices message. The search never appears to end (perhaps because TIMEOUT=-1 in fwupd-dbus/src/lib.rs ?) and therefore the view_empty state is never reached and the panel remains blank.

Firmware update prompted for non-up-to-date version

Hi, after installing the latest gnome control center update with the new firmware manager tab, it prompted me to update the thinkpad system firmware on my P50. This with a version older than the one I have installed already.
I suspect this has everything to do with the fact that I updated the firmware with Lenovo's tool on the Windows install of the machine and that wherever linux sources its firmware from hasn't caught up yet. But I suppose it might make sense to include a check whether a detected version mismatch is also more current.

Screenshot from 2019-08-17 10-49-21

Phrasing of system upgrade pop-up is strange

Currently the pop-up for system firmware notifications says: Fixes and features include: and then lists the changelog. Potentially that is a little odd, as showing the changelog of versions prior to what is installed isn't really showing what fixes and features are included in the update.

Screenshot from 2019-08-16 08-24-59

Maybe change the wording to just state that the following is a changelog? Or show only the changelog containing the latest update?

firmware-manager does not install Ubuntu 18.04

To add the firmware packages on Ubuntu 18.04 I ran:

git clone https://github.com/pop-os/pop
./pop/scripts/apt add firmware --dev
sudo apt update
sudo apt upgrade

sudo apt update then shows that there is 1 application to be upgraded but neither sudo apt upgrade nor sudo apt full-upgrade upgrades the package. Further investigation shows the following issue:

system76@system76-pc:~$ apt policy system76-driver
system76-driver:
  Installed: 19.04.12~1565034523~18.04~e2801c1~dev
  Candidate: 19.04.15~~alpha~1565816384~18.04~4001991~dev
  Version table:
     19.04.15~~alpha~1565816384~18.04~4001991~dev 1002
       1002 http://apt.pop-os.org/staging-ubuntu/firmware bionic/main amd64 Packages
     19.04.14~1565295911~18.04~d8fec20~dev 500
        500 http://ppa.launchpad.net/system76-dev/stable/ubuntu bionic/main amd64 Packages
 *** 19.04.12~1565034523~18.04~e2801c1~dev 100
        100 /var/lib/dpkg/status
system76@system76-pc:~$ sudo apt install system76-driver=19.04.15~~alpha~1565816384~18.04~4001991~dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 system76-driver : Depends: firmware-manager-virtual but it is not installable
E: Unable to correct problems, you have held broken packages.

Refreshing metadata from LVFS on every run is overkill

I find that running firmware-manager-gtk metadata is fetched on every single launch of the application, which is overkill. I would recommend to cache that metadata and only look once per day (unless the refresh button in the UI is clicked).

Open device firmware changlog when a device is clicked

For both system and device firmware, open the devices firmware changlog when a device is clicked using the same dialog that's used for system firmware updates.

If an update is available, offer an Update button. Close the window once Update is clicked (progress is shown in the panel).

Firmware tab appears in Ubuntu 18.04

With just the firmware staging branch added, a firmware tab in gnome-control-center is still being added. This integration for gnome-control-center should only happen on Pop!_OS.

EDIT: Removed screenshot because it was an outdated screenshot

darp5: Opening firmware tab in Gnome Settings has poorly alligned content

On the Darter Pro, when selecting the Firmware tab, the sections are formatted incorrectly (not wide enough)

Not good:
Screenshot from 2019-07-29 09-41-09

Good:
Screenshot from 2019-07-29 09-26-51

I am unable to recreate this issue with the same result on thelio-r1 but when the page is loading initially I do see the page, for a moment, is formatted similarly before resizing and fixing itself.
bug

Connect to A/C message should be smart about when to be displayed

Currently on all system firmware updates, there is a message at the bottom of the pop-up menu that tells the user if the machine they are on is a laptop, to plug in the laptop before running the update.

It should be possible to determine if the machine is a laptop or desktop and only show a message when the machine is a laptop.

Update firmware page in GNOME-Control-Center after dismissing error message

Background: I wanted to test what would happen if after opening the firmware page with an update available for a fwupd device (a mouse), if I disconnected the mouse what would happen when attempting to update the nonconnected mouse. As is appropriate, an error appears.

Issue: When dismissing the error, the page does not refresh so the button to update a disconnected device still exists. In discussion with @jackpot51 it seems to make sense to refresh/update the page whenever dismissing an error message.

Firmware manager page is blank when the system is offline

When there is no network connection, currently an error appears error trying to connect.

When a system is offline and not connected to a network, this page should still be able to show the currently installed firmware (just not be able to check for updates).

Build from source not finding git repo?

I'm on CentOS 7 (Rust 1.36.0 which I think is recent enough) and after a Makefile tweak I mentioned in another issue (#47), I'm hitting a git access issue that stops the build immediately. I ran both:

make prefix=/usr features='fwupd system76'

and

make prefix=/usr features='fwupd'

(I don't have a System76 system, hence trying the second version as well) and both resulted in git access errors:

Updating git repository https://github.com/pop-os/system76-firmware
error: failed to load source for a dependency on system76-firmware-daemon

Caused by:
Unable to update https://github.com/pop-os/system76-firmware?branch=firmware-client#f77915c0

Caused by:
revspec 'f77915c0a3d23b7f4db0473e5956173fbecdc4eb' not found; class=Reference (4); code=NotFound (-3)

This is after checking out the source both with "git clone" and also just downloading the master zip file from Github and unpacking that. It appears that whatever git repo the build is expecting isn't there.

BTW, with the features='fwupd' build, why is it still trying to access the System76 code?

Unavailable firmware message should only appear after searching for firmware

When switching from a different settings tab to the Firmware tab, very briefly the "Managed Firmware Unavailable: No devices supporting automatic firmware updates detected" is shown. As it only appears for a brief moment, it appears jarring (not to mention incorrect). Perhaps wait to show that message until making an attempt to look for supported firmware first?

Design

Integrate automatic firmware updates into Pop!_OS via a system library that displays in gcc (Devices > Firmware) and daemon that checks for updates and provides notifications. The library and daemon can be installed on other distributions for system76 firmware updates. Both will be installed for system76 customers using Ubuntu probably with the system76-driver package.

Firmware-panel-no-managed-devices

"System Firmware" is firmware that requires a reboot to install.

Firmware-panel

System and device firmware update clicked

Transition from system76-driver's firmware UI

  • Release fwupd with privacy concerns addressed (@jackpot51)
  • Release firmware-manager, but do not depend on it yet (@mmstick)
    • Add autostart file to show notifications by running firmware-manager in the background without a UI
    • The notification should launch the gnome-control-center firmware pane if the desktop file for it can be found, and launch the firmware-manager application otherwise
  • Perform testing on firmware-manager (@brs17)
    • Find a way to roll back or simulate fwupd updates
    • Test update notifications
    • Test use in Ubuntu or alternative Desktop Environments
  • Prepare a branch of gnome-control-center with the following (@mmstick):
    • Firmware pane that shows up in GNOME Shell
    • Hide firmware-manager from GNOME Shell, potentially by using dpkg-divert or NoDisplay=True if and only if gnome-control-center with a Firmware pane is installed
  • Prepare a branch of system76-driver with the following (@jackpot51):
    • Depends on firmware-manager
    • Remove system76-firmware tool
    • Remove desktop file and autostart

Progress bar does not reach completion

Noticed while updating thelio-io board firmware, the progress bar makes it 80/90% through before disappearing as the installation is complete. Progress bars should complete when/if the associated task completes.

gaze14: System firmware update pop-up fails to launch

With a firmware update available on the gaze14, selecting the Update button opens a blank window with the inability to update the firmware.

When launched from the terminal, gnome-control-center returns an error message: Gtk-CRITICAL **: 07:40:54.541: gtk_container_foreach: assertion 'GTK_IS_CONTAINER (container)' failed

Screenshot from 2019-08-14 07-41-00

System firmware does not need a progress bar

With system firmware already downloaded before notifying the user of new firmware, the progress bar shown after selecting reboot shows up for a split second providing no real value to the user.

This progress bar c/should probably just be removed from system firmware updates.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.