blob: 04f6087886a021036ef9278f1c86c7da0ddb99c2 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GARNET_LIB_UI_GFX_ENGINE_RESOURCE_LINKER_H_
#define GARNET_LIB_UI_GFX_ENGINE_RESOURCE_LINKER_H_
#include <unordered_map>
#include <unordered_set>
#include <lib/async/cpp/wait.h>
#include <lib/fit/function.h>
#include "lib/fsl/handles/object_info.h"
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include "garnet/lib/ui/gfx/engine/unresolved_imports.h"
#include "garnet/lib/ui/gfx/resources/resource.h"
namespace scenic_impl {
namespace gfx {
/// Allows linking of resources in different sessions.
/// Accepts a resource and one endpoint of an event pair for export. That
/// exported resource can be imported in another session by providing the peer
/// for the token used in the export call. The same exported resource can be
/// imported multiple times by duplicating the peer token and making the import
/// call multiple times with each duplicated token.
///
/// The linker owns the tokens provided in the export calls and handles cases
/// where the import call arrives before the resource that matches that query
/// has been exported.
///
/// A resource can be exported multiple times; we refer to one of those
/// times as an "export."
///
/// There are two ways an export can be removed: Either the resource is
/// destroyed using |OnExportedResourceDestroyed|, or all the import tokens have
/// been closed which results in a call to |RemoveExportEntryForExpiredKoid|.
class ResourceLinker {
public:
ResourceLinker();
~ResourceLinker();
// Register a |resource| so that it can be imported into a different session
// via ImportResourceCmd with the peer of |export_token|.
//
// Returns true if there are no errors.
bool ExportResource(Resource* resource, zx::eventpair export_token);
// Registers an |import| with a given |spec| and |import_token|. |import| is
// new resource in the importing session that acts as a import for a resource
// that was exported by another session.
//
// Since the other end (the resource being imported) might not be registered
// yet, the binding is not guaranteed to happen immediately.
//
// Returns true if there are no errors.
bool ImportResource(Import* import, ::fuchsia::ui::gfx::ImportSpec spec,
zx::eventpair import_token);
size_t NumExports() const;
size_t NumUnresolvedImports() const;
enum class ExpirationCause {
kInternalError,
kNoImportsBound,
kExportTokenClosed,
kResourceDestroyed,
};
using OnExpiredCallback = fit::function<void(Resource*, ExpirationCause)>;
void SetOnExpiredCallback(OnExpiredCallback callback);
using OnImportResolvedCallback =
fit::function<void(Import*, Resource*, ImportResolutionResult)>;
void SetOnImportResolvedCallback(OnImportResolvedCallback callback);
size_t NumExportsForSession(Session* session);
// To prevent making any requirements about the lifecycle of ResourceLinker
// compared to resources, always refer to ResourceLinker with a weak pointer.
fxl::WeakPtr<ResourceLinker> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
friend class UnresolvedImports;
friend class Resource;
friend class Import;
// Remove exports for this resource. Called when the resource is being
// destroyed.
void OnExportedResourceDestroyed(Resource* resource);
// A callback that informs us when an import has been destroyed.
void OnImportDestroyed(Import* import);
void OnImportResolvedForResource(Import* import, Resource* actual,
ImportResolutionResult resolution_result);
void OnTokenPeerDeath(zx_koid_t import_koid, zx_status_t status,
const zx_packet_signal* signal);
void InvokeExpirationCallback(Resource* resource, ExpirationCause cause);
Resource* RemoveExportEntryForExpiredKoid(zx_koid_t import_koid);
void RemoveExportedResourceIfUnbound(Resource* exported_resource);
// Returns true if a link was made.
bool PerformLinkingNow(zx_koid_t import_koid);
// Helper method to remove |import_koid| from |resources_to_import_koids_|.
void RemoveFromExportedResourceToImportKoidsMap(Resource* resource,
zx_koid_t import_koid);
struct ExportEntry {
zx::eventpair export_token;
std::unique_ptr<async::Wait> token_peer_death_waiter;
Resource* resource;
};
using ImportKoid = zx_koid_t;
using KoidsToExportsMap = std::unordered_map<ImportKoid, ExportEntry>;
using ResourcesToKoidsMap = std::multimap<Resource*, ImportKoid>;
OnExpiredCallback expiration_callback_;
OnImportResolvedCallback import_resolved_callback_;
KoidsToExportsMap export_entries_;
ResourcesToKoidsMap exported_resources_to_import_koids_;
// |exported_resources_| can contain resources that are not included in the
// maps above. Even if all the import tokens for a given export are destroyed,
// the associated resource could still be exported because it's already been
// bound to an import.
std::unordered_set<Resource*> exported_resources_;
UnresolvedImports unresolved_imports_;
fxl::WeakPtrFactory<ResourceLinker> weak_factory_; // must be last
FXL_DISALLOW_COPY_AND_ASSIGN(ResourceLinker);
};
} // namespace gfx
} // namespace scenic_impl
#endif // GARNET_LIB_UI_GFX_ENGINE_RESOURCE_LINKER_H_