[Fontconfig] Next steps for a reproducible Fontconfig?
Alexander Larsson
alexander.larsson at gmail.com
Sun Jan 13 11:52:59 UTC 2019
On Fri, Jan 11, 2019 at 11:07 PM Keith Packard <keithp at keithp.com> wrote:
>
> Alexander Larsson <alexander.larsson at gmail.com> writes:
>
> A .uuid file was added and removed to every directory in the font tree
> which contained no fonts or sub-directories; (a) the directory mtime was
> changed, causing the system to re-scan the fonts and then
> re-create/re-delete the .uuid file (goto a). Somehow this would
> eventually stablize (I'm not entirely sure how). It was a 'surprising'
> problem that happened only once in a while and it took several days of
> searching to locate as the only symptom was that firefox would hang for
> 'a while' and then start working. Once I ran strace on the process while
> hung, it was pretty easy to track down, but having fontconfig affecting
> directory mtimes was not what I expected...
Ugh. Sorry about that!
> > However, the second problem is that it puts demands on the *host*, as
> > it now has to match the layout of the runtimes so the pathnames can
> > match identically.
>
> Well, I was thinking that the runtime would dynamically adapt to the
> host environment and change the configuration inside to match the
> host.
>
> Is it that flatpak treats fonts very specially, or are there other bits
> of host data injected into the flatpak runtime in a similar fashion?
The point of any kind of container system is that you can have a
container filesystem that is guaranteed (to some 99% extent anyway) to
be the same wherever you run it. This way any kind of testing and
hardcoding you do on your system will be valid on the users system,
elimiting a whole form of bugs.
There are also technical issues with doing this. First of all, the
runtime (which is basically a directory that gets mounted on /usr have
no real requirements, its up to whoever create it to decide how and
what goes in there. So, say the host stores fonts in /usr/data/fonts
or whatever here might not be a corresponding directory in the runtime
to bind-mount on top of. And if there is there is no guarantee that
its not used for something else.
Basically, flatpak lets the runtime have full control of /usr, and
anything special (i.e. not direct mappings of directories the sandbox
is supposed to have access too) that we inject in the sandbox is in
/run.
There are a bunch of stuff we inject in the sandbox other than fonts,
but not a lot. First of all there are various unix domain sockets for
things like dbus, X11, etc. Then fonts, icon themes, timezone config,
resolv config, and the host /usr (as /run/host/usr) if the sandbox has
full filesystem access.
> Essentially, I was imagining the flatpak runtime system would discover
> the set of fontconfig directories exposed by the host and inject those
> into the runtime using matching paths. Right now, you inject two fixed
> paths (/usr/share/fonts and ~/.fonts), but if we really want to deal
> with systems that put fonts in other places, then presumably flatpak
> will need to adapt anyways.
They are fixed, but at flatpak build time, so a "weird" system could
configure flatpak to pick them up elsewhere, while exposing them in a
standardized location in the sandbox. True, this only allows two
directories, but I don't think this is really a huge issue in
practice.
> > Maybe "weird" setups like nix will run into issues. You might know
> > this better.
>
> Good point; as new distros start experimenting with different filesystem
> layouts, we will need to be more cautious about assuming fixed paths
> of any kind.
Same with experimenting with the layout of the runtime itself.
> > Yes, but if you update the runtime and /usr/share/fonts-minimal
> > changed in the new version (but has same mtime), then the stale cache
> > file in the users homedir will still be used.
>
> Ah. Thanks for explaining this. It seems like the only way this could
> happen is if the cache file within the flatpak was stale and a
> replacement generated and written to the user's homedir (as the only
> writable location available).
Yes:ish. It should not *normally* happen. But you may run into it in
uncommon situations like e.g. chrome using a statically linked version
of fontconfig that has a different fontconfig cache format.
> > However, flatpak will never parse the entire xml fontconfig file
> > format (which isn't even really stable over time), so such a config
> > would have to be external in a simpler config format.
>
> The fontconfig xml format is quite stable and is designed to be
> manipulated by tools that do not understand the full contents, hence
> using XML and providing a suitable DTD.
We recently ran into issues with fontconfig xml parsing errors in chrome
when using config files from a newer host fontconfig that were not
parsable by the statically linked chrome copy, so it is not perfect.
Additionally there is a question of forward compat. If flatpak was to
generate a "new" xml option that older fontconfigs were using, then we
would not support existing runtimes with older fontconfigs in it.
So, what we need is to be able to create snippets that get included by
the runtime config, added to the runtime at the same time as the
fontconfig in the runtime is updated to support it. These snippets can
be xml of course, but its different than parsing the entire fontconfig
xml config file in the runtime and understanding+modifying that.
> > Currently the runtime contains a static conf.d snippet that says:
> > <dir>/run/host/fonts</dir>
> > <dir>/run/host/user-fonts</dir>
> >
> > We would have to turn that into a dynamic snippet. But that would be a
> > problem for pre-existing flatpak binaries which doesn't do this.
>
> Any existing flatpaks will presumably include an existing fontconfig
> which will not use font caches for the host which will not have .uuid
> files in each directory anyways. As long as those existing flatpaks
> "work" by re-generating the cache at first start, that seems fine to
> me. Re-create those flatpaks with new fontconfig bits and things will
> work better.
I agree with this, but the point was that we can't just modify the
fontconfig to be dynamic always. We need to design it such that
whatever flatpak generates is optional for the runtime to pick up when
it is able to handle it.
> > Flatpak generates at startup a file like this in /run/host/fontconf.xml
> >
> > <cache-as path="/usr/share/fonts">/run/host/fonts></cache-as>
> > <cache-as path="/home/alex/.fonts">/run/host/user-fonts></cache-as>
> >
> > In the runtime we create at build-time a /etc/fonts/conf.d/ file:
> >
> > <salt id="randomdata">/usr/share/fonts</salt>
> > # Duplicate this with static versions for old flatpak versions
> > <cache-as path="/usr/share/fonts">/run/host/fonts></cache-as>
> > # This will (if it exists) override the above with the live values
> > <include ignore_missing="yes">/run/host/fontconf.xml</include>
>
> I think you'll want two separate files -- the salt is "constant" for the
> flatpak, while the cache-as values depend on the host
> environment. Otherwise, this looks good to me.
Yeah, there will be two files. One static in the runtime
(/etc/fonts/conf.d/50-flatpak.xml), and one generated by flatpak
(/run/host/fontconf.xml).
The idea would be that if you're using flatpak 1.0 (current stable)
then there will be no dynamic /run/host/fontconf.xml generated, while
in 1.2 (soon to be released) there will be one. So, to support 1.0
somewhat we hardcode the /run/host/fonts=/usr/share/fonts config in
the static file, and on >= 1.2 we override that in the dynamic to the
correct location. Then we still get to reuse the host caches in old
flatpaks in the "normal" font path case.
Of course, we could also rely on "old flatpk == old fontconfig",
meaning the host has uuid files... That might be enough to handle old
installations.
More information about the Fontconfig
mailing list