[go: nahoru, domu]

tree: fd938964e7ef9d5ab56277d18dd1c95ea0e12329 [path history] [tgz]
  1. BUILD.gn
  2. DIR_METADATA
  3. fusebox_copy_to_fd.cc
  4. fusebox_copy_to_fd.h
  5. fusebox_errno.cc
  6. fusebox_errno.h
  7. fusebox_errno_unittest.cc
  8. fusebox_moniker.cc
  9. fusebox_moniker.h
  10. fusebox_moniker_unittest.cc
  11. fusebox_read_writer.cc
  12. fusebox_read_writer.h
  13. fusebox_server.cc
  14. fusebox_server.h
  15. OWNERS
  16. README.md
chrome/browser/ash/fusebox/README.md

Fusebox

Fusebox is a ChromeOS-only mechanism for exposing Chrome's in-process virtual file system (its storage C++ API) on the ‘real’ (kernel-level) virtual file system, via Linux's FUSE protocol.

It enables sharing virtual-file-like things across processes (e.g. between ash-chrome and lacros-chrome) or with Virtual Machines (e.g. the Android or Crostini VMs) just by sharing a string file name or an integer file descriptor.

Fusebox doesn't replace the storage C++ API. It provides an alternative mechanism for accessing those virtual files. Workflows that stay entirely within ash-chrome can continue to use the C++ API. But when the GMail web-app (running in a sandboxed lacros-chrome process) wants to upload files from a phone attached to a Chromebook via USB cable, and the MTP (Media Transfer Protocol) volume (virtual directory) is served by ash-chrome code, that access is facilitated by Fusebox.

Structure

There are multiple processes involved. The two key ones communicate over D-Bus:

  • ash-chrome is the D-Bus server, also known as the Fusebox Server. This process does not speak FUSE per se.
  • /usr/bin/fusebox is the D-Bus client, also known as the Fusebox Client or the Fusebox Daemon. This is the process that speaks FUSE with the kernel. Like other FUSE daemons on ChromeOS, this is managed by cros-disks and runs in a minijail sandbox.

Those are the two key processes. More processes are involved when an arbitrary process (e.g. lacros-chrome or another process running in an Android VM) wants to read a Fusebox file:

arbitrary-proc  <-libc->  kernel  <-FUSE->  FuseboxDaemon  <-D-Bus->  ash-chrome

Specifically when “an arbitrary process” is lacros-chrome, we could skip some hops with a direct connection between lacros-chrome and ash-chrome. But that optimization is not implemented yet (as of March 2023).

cros-disks forks/execs the Fusebox Daemon at user log-in. But after start-up, cros-disks is not involved in Fusebox serving virtual files.

D-Bus

The Fusebox Server has some bookkeeping code because D-Bus RPCs are “1 request, 1 response” but some storage C++ API calls are “1 request, multiple (streaming) responses”. In Fusebox's D-Bus protocol, the cookie is the common numeric identifier that groups these request/response pairs.

We may move our IPC system from D-Bus to Mojo in the future, for this and other reasons, especially as we don‘t really use D-Bus’ structured types anymore (they‘re hard to evolve, since the client and server live in different source code repositories). Fusebox only uses D-Bus as a simple pipe for flinging Fusebox-specific protobufs around. But for now (March 2023), it’s D-Bus.

The method names on Fusebox' D-Bus interface (e.g. “Open”, “Read”, “Write”, etc.) typically correspond 1:1 with both FUSE methods and Chrome's storage C++ API methods, although those two systems sometimes use different names (e.g. “Unlink” and “Rmdir” versus “RemoveFile” and “RemoveDirectory”).

Some method names have a “2” suffix, “Read2” versus “Read”, because the original version used D-Bus' structured types as arguments. As above, these are hard to evolve (e.g. add a new field) without atomic cross-repository commits. The “2” versions speak protobufs-over-D-Bus instead.

File Names

Fusebox file names (on the kernel-visible file system) look like /media/fuse/fusebox/abc.1234/foo/bar.txt. The abc.1234 is also called the Fusebox Subdir (or just the Subdir), as a single Fusebox daemon process can serve multiple volumes.

The abc part of the Subdir identifies the volume type:

  • adp = Android Documents Provider, an Android (Java) API. For example, Dropbox has an official Android app, which can run on Chromebooks, making someone's Dropbox folder-in-the-cloud appear in the ChromeOS Files App.
  • fsp = File System Provider, a Chrome (JavaScript) API. For example, Chrome extensions can implement virtual file systems.
  • mtp = Media Transfer Protocol, via ChromeOS' system-global platform2/mtpd daemon. For example, phones and tablets that are attached to a Chromebook via USB cable and have opted in to sharing their files.
  • tmp = Temporary filesystem (a subdirectory of /tmp), for testing.

The 1234 part of the Subdir, typically a base-64 encoded hash code, identifies different volumes of that type. For example, somebody could mount multiple ADP volumes, and they‘d get different adp.* Subdirs. These hashes (and hence file names) aim to be stable for what’s conceptually “the same volume”. For example, unplugging a phone from a USB port and plugging the same phone into a different port shouldn't change the Subdir.

The foo/bar.txt part is the relative path within the volume root. For example, Download/cake.jpg could identify a photo in an attached phone's Download directory.

Built-In File Names

The Fusebox Client also serves some files under /media/fuse/fusebox/built_in, mainly for basic debugging. For example, some of these built_in files may still be informative even when the Fusebox Client cannot connect to the Fusebox Server.

Source code

The Fusebox Server (Chrome) code primarily lives in this directory, chrome/browser/ash/fusebox. Unsurprisingly, fusebox_server.cc is the centerpiece. Part of its code is bureaucracy because D-Bus code and callbacks run on the main (UI) thread while storage code and callbacks run on the IO thread. Blocking I/O belongs on yet another thread (or a pool of worker threads).

A little bit of Fusebox-specific D-Bus bureaucracy lives in the fusebox_service_provider.* files in a sibling directory, chrome/browser/ash/dbus.

Fusebox integration with the Files App (ChromeOS' graphical file manager), via its “under the hood” Volume Manager, and related “talk to cros-disks” code lives in another sibling directory, chrome/browser/ash/file_manager.

The Fusebox Client code lives in the fusebox directory in the platform2 repository.

storage C++ API

The Fusebox Server layers over Chrome‘s storage C++ API. The interface’s source code lives in the storage/browser/file_system directory and backing implementations are elsewhere. For example:

  • the ADP implementation is in chrome/browser/ash/arc/fileapi.
  • the FSP implementation is in chrome/browser/ash/file_system_provider/fileapi.
  • the MTP implementation is in chrome/browser/media_galleries/fileapi.
  • the ‘real’ file system implementation is in storage/browser/file_system.

storage was historically designed around serving a cross-browser JS API, allowing multiple, independent web apps (each running untrusted code) to access persistent storage without interfering with each other. Fusebox uses it (e.g. storage::FileSystemURL) largely because that‘s how Chrome’s ‘Virtual File Systems’ are implemented. Some storage::FileSystemURL concepts such as their url::Origin and blink::StorageKey are core to the API but less relevant for Fusebox's use.

FUSE Handles

When the kernel sends the FUSE server an “open” request (and a string path), the response contains a numeric FUSE handle (sometimes abbreviated as fh, just like how a numeric file descriptor can be fd). Subsequent “read” requests contain the handle but not the path.

These FUSE Handle numbers are similar to inode numbers, in that they're server-defined and opaque to the client, but they are not the same. Just as the one file can be opened multiple times, the one inode can be associated with multiple file descriptors (on the ‘file system client’ side) and multiple FUSE handles (on the ‘file system server’ side).

Monikers

Monikers are a Fusebox concept (but not a FUSE concept). They are similar to symlinks, in that they are an alternative name to an existing thing. They are unlike symlinks in that the link target does not otherwise exist on the ‘real’ file system. The link target is a storage::FileSystemURL.

Fusebox Monikers are used for ad-hoc sharing on demand, typically for individual files instead of directories or volumes. They are for “share this one (virtual) file with only this one app” rather than “make this folder-in-the-cloud available as an ambient collection of (virtual) files”.

Moniker file names look like /media/fuse/fusebox/moniker/123etc789. moniker is the entire Subdir and the 123etc789 is an unguessable random number.

See the fusebox_moniker.h comments for more detail.

Testing

As the interesting parts of Fusebox involve multiple processes (Fusebox Client, Fusebox Server and more), we rely more on integration tests (tast) than unit tests. The test code lives in the platform repository, under tast-tests/src/chromiumos/tast/local/bundles/cros/filemanager/.

More Information

Here are some Google-internal slide decks (the speaker notes also link to video recordings):

There's also the ChromeOS Files Team site for more general information. It is also Google-internal.