// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module crosapi.mojom;
import "mojo/public/mojom/base/file_path.mojom";
import "mojo/public/mojom/base/values.mojom";
import "ui/gfx/image/mojom/image.mojom";
// A file system is uniquely identified by an opaque string (consisting of at
// least the extension id + profile unique identifier) and a file_system_id.
[Stable]
struct FileSystemId {
// At a minimum, identifies the extension. May also need to identify profiles
// in the future.
string provider@0;
// A unique id (for a particular |provider|) provided by the extension.
string id@1;
};
// The primary data source for the file system.
[Stable, Extensible]
enum FileSystemSource {
[Default] kFile,
kNetwork,
kDevice
};
// Provides immutable metadata about a file system.
[Stable]
struct FileSystemMetadata {
// The identifier of the file system.
FileSystemId file_system_id@0;
// A human-readable name for the file system.
string display_name@1;
// Whether the file system supports operations which may change contents of
// the file system (such as creating, deleting or writing to files).
bool writable@2;
// The maximum number of files that can be opened at once. If 0, then not
// limited.
uint32 opened_files_limit@3;
// Whether the file system supports the tag field for observing directories.
bool supports_notify@4;
};
// Files can be opened either for reading or writing.
[Stable, Extensible]
enum OpenFileMode {
[Default] kRead,
kWrite,
};
[Stable]
struct OpenedFile {
// A request ID to be be used by consecutive read/write and close requests.
int64 open_request_id@0;
// The path of the opened file. While it seems like it would make sense to use
// a base::Path, both the extension API and the ash FileSystemProvider API
// pass strings.
string file_path@1;
// Whether the file was opened for reading or writing.
OpenFileMode mode@2;
};
// Represents a watcher.
[Stable]
struct FSPWatcher {
// The path of the entry being observed.
mojo_base.mojom.FilePath entry_path@0;
// Whether watching should include all child entries recursively. It can be
// true for directories only.
bool recursive@1;
// Tag used by the last notification for the watcher.
string last_tag@2;
};
[Stable]
struct FileSystemInfo {
// Fixed metadata about the file system.
FileSystemMetadata metadata@0;
// List of currently opened files.
array<OpenedFile> opened_files@1;
// List of watchers.
array<FSPWatcher> watchers@2;
};
[Stable, Extensible]
enum FSPChangeType {
[Default] kChanged,
kDeleted
};
[Stable]
struct CloudFileInfo {
string? version_tag@0;
};
[Stable]
struct FSPChange {
// Next MinVersion: 2
FSPChangeType type@0;
mojo_base.mojom.FilePath path@1;
[MinVersion=1] CloudFileInfo? cloud_file_info@2;
};
[Stable, Extensible]
enum FSPOperationResponse {
// Next MinVersion: 2
[Default] kUnknown,
kUnmountSuccess,
kGetEntryMetadataSuccess,
kGetActionsSuccess,
kReadDirectorySuccess,
kReadFileSuccess,
kGenericSuccess,
kGenericFailure,
[MinVersion=1] kOpenFileSuccess,
};
[Stable, Extensible]
enum FSPForwardResult {
[Default] kUnknown,
kSuccess,
kInternalError,
kNoListener,
};
// Implemented by Lacros.
[Stable, Uuid="8cbcf151-c189-4fe9-90ff-892c7f5637a9"]
interface FileSystemProvider {
// Allows Ash to forward requests to Lacros extension providers.
// We use mojo_base.mojom.Value as the type because:
// * The extension API is stable.
// * Both the supplier and consumer of this information uses a type
// interchangeable with mojo_base.mojom.Value. While we could add a
// translation layer to a strongly typed mojom struct, this adds a
// overhead and the potential for errors with no benefit.
// Similarly, histogram_value is an int32 instead of the native enum
// HistogramValue because the enum is stable, has hundreds of entries, and
// cannot be type-mapped due to build-time dependency inversions.
// Provider will typically be an extension_id but is intentionally left
// abstract to support multi-profile in the future.
// |delivery_failure| is set to true if the operation could not be forwarded
// to the extension for any reason.
[MinVersion=1]
DeprecatedDeprecatedForwardOperation@0(
string provider, int32 histogram_value, string event_name,
array<mojo_base.mojom.Value> args);
[MinVersion=2]
DeprecatedForwardOperation@1(
string provider, int32 histogram_value, string event_name,
array<mojo_base.mojom.Value> args) => (bool delivery_failure);
[MinVersion=3]
ForwardOperation@2(
string provider, int32 histogram_value, string event_name,
mojo_base.mojom.ListValue args) => (bool delivery_failure);
// Same as ForwardOperation, but exposes request metadata uniquely identifying
// a request. A request is uniquely identified by a tuple of:
// - |provider|, |file_system_id|, |request_id|: for requests addressed to a
// specific file system instance.
// - |provider|, |request_id|: for requests addressed to a provider in general
// (e.g. a request to mount a new filesystem). In this case,
// |file_system_id| will be null.
[MinVersion=4]
ForwardRequest@3(
string provider, string? file_system_id, int64 request_id,
int32 histogram_value, string event_name,
mojo_base.mojom.ListValue args) => (FSPForwardResult result);
// Signal to Lacros that Ash cancelled a request uniquely identified by
// given parameters.
[MinVersion=4]
CancelRequest@4(
string provider, string? file_system_id, int64 request_id);
};
// Implemented by Ash. Extensions in Lacros can register themselves as file
// system providers. As the underlying system in Ash already supports
// multiplexing, we refrain from introducing a second layer of multiplexing at
// the crosapi layer. Lacros registers itself as a FileSystemProvider at
// startup. Extensions will call the "mount" method to make themselves known to
// Ash. At that point, Ash will send operations via FileSystemProvider, which
// Lacros will fulfill by calling methods in FileSystemProviderService. This
// creates a state machine with state spread between Ash and Lacros. This is
// dispreferred but unfortunately impossible to avoid given the design of the
// fileSystemProvider extension API.
[Stable, Uuid="82db93f7-e0a5-4a9c-a09f-db92f9e45348"]
interface FileSystemProviderService {
// File system providers use this interface to receive operation requests.
RegisterFileSystemProvider@0(pending_remote<FileSystemProvider> provider);
// Makes a filesystem provided by an extension visible to the operating system
// and other consumers.
Mount@1(FileSystemMetadata metadata, bool persistent) => (string error);
// Makes a filesystem provided by an extension unavailable.
Unmount@2(FileSystemId file_system_id) => (string error);
// Returns all file systems mounted by the extension.
GetAll@3(string provider) => (array<FileSystemInfo> infos);
// Returns information about a file system with the passed file_system_id.
Get@4(FileSystemId file_system_id) => (FileSystemInfo? info);
// Called by the extension to notify watchers of changes.
// |file_system_id| is the identifier of the file system related to this
// change.
// |watcher| gives information about the path being observed, including the
// tag.
// |type| provides information about the observed entry.
// |changes| provides information about the observed directory.
// Note: for backwards compatibility with the existing extension API, both
// |type| and |changes| are necessary even though they appear mutually
// exclusive.
Notify@5(FileSystemId file_system_id, FSPWatcher watcher,
FSPChangeType type, array<FSPChange> changes) => (string error);
// The following function represents responses from the Extension after
// handling an operation. We use mojo_base.mojom.Value as the type because:
// * The extension API is stable.
// * Both the supplier and consumer of this information uses a type
// interchangeable with mojo_base.mojom.Value. While we could add a
// translation layer to a strongly typed mojom struct, this adds a
// overhead and the potential for errors with no benefit.
// |request_id| corresponds to ids passed in via methods on interface
// FileSystemProvider.
[MinVersion=1]
DeprecatedOperationFinished@6(FSPOperationResponse response,
FileSystemId file_system_id, int64 request_id,
array<mojo_base.mojom.Value> args) => (string error);
[MinVersion=3]
OperationFinished@9(FSPOperationResponse response,
FileSystemId file_system_id, int64 request_id,
mojo_base.mojom.ListValue args) => (string error);
// Handles return the success callback from the `OpenFile` method after the
// optional metadata dictionary support was added.
// The underlying functionality behaves similarly to the `OperationFinished`
// method above, however, having it as an interface method enables validating
// whether the remote version supports the callback or not.
[MinVersion=6]
OpenFileFinishedSuccessfully@12(FileSystemId file_system_id,
int64 request_id,
mojo_base.mojom.ListValue args) => (string error);
// The following function represents responses from the Extension after
// handling a mount request. As opposed to `OperationFinished`, these
// requests are handled per-provider instead of per provided file system
// (no `FileSystemId).
// |request_id| corresponds to ids passed in via methods on interface
// FileSystemProvider.
[MinVersion=4]
MountFinished@10(string extension_id, int64 request_id,
mojo_base.mojom.ListValue args) => (string error);
// Called by Lacros when a filesystem providing extension is loaded.
[MinVersion=2]
ExtensionLoadedDeprecated@7(
bool configurable, bool watchable, bool multiple_mounts,
FileSystemSource source, string extension_name, string extension_id);
// Called by Lacros when a filesystem providing extension is loaded. This
// version passes the extension's icons to use in the file browser.
[MinVersion=5]
ExtensionLoaded@11(
bool configurable, bool watchable, bool multiple_mounts,
FileSystemSource source, string extension_name, string extension_id,
gfx.mojom.ImageSkia? icon16x16, gfx.mojom.ImageSkia? icon32x32);
// Called by Lacros when a filesystem providing extension is unloaded.
[MinVersion=2]
ExtensionUnloaded@8(string id, bool due_to_shutdown);
};