blob: dc95b1c076c52e1ab495e79065be4bf15e3286d4 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// MountTask - The basis for asynchronous API work items. It inherits from
// Task, which allows it to be called on an event thread. Subclasses define the
// specific asychronous request.
// Asynchronous tasks in cryptohome are serialized calls on a single worker
// thread separate from the dbus main event loop. The synchronous versions of
// these APIs are also done on this worker thread, with the main thread waiting
// on a completion event to return. This allows all of these calls to be
// serialized, as we use a common mount point for cryptohome.
// Also defined here is the MountTaskResult, which has the task result
// information, and the MountTaskObserver, which is called when a task is
// completed.
// Notifications can happen either by setting the completion event or providing
// a MountTaskObserver. The former is used in Service (see when
// faking synchronous versions of these tasks, and the latter is used in the
// asynchronous versions.
#include <memory>
#include <base/atomic_sequence_num.h>
#include <base/atomicops.h>
#include <base/memory/ref_counted.h>
#include <base/observer_list_types.h>
#include <base/synchronization/atomic_flag.h>
#include <base/synchronization/waitable_event.h>
#include <base/threading/thread.h>
#include <brillo/process/process.h>
#include <brillo/secure_blob.h>
#include "cryptohome/credentials.h"
#include "cryptohome/cryptohome_event_source.h"
#include "cryptohome/mount.h"
#include "cryptohome/pkcs11_init.h"
namespace cryptohome {
extern const char* kMountTaskResultEventType;
extern const char* kPkcs11InitResultEventType;
class InstallAttributes;
class MountTaskResult : public CryptohomeEventBase {
using SecureBlob = brillo::SecureBlob;
: sequence_id_(-1),
guest_(false) {}
// Constructor which sets an alternative event name. Useful
// for using MountTaskResult for other event types.
explicit MountTaskResult(const char* event_name)
: sequence_id_(-1),
guest_(false) {}
// Copy constructor is necessary for inserting MountTaskResult into the events
// vector in CryptohomeEventSource.
MountTaskResult(const MountTaskResult& rhs)
: sequence_id_(rhs.sequence_id_),
guest_(rhs.guest_) {
if (rhs.return_data())
virtual ~MountTaskResult() {}
// Get the asynchronous task id
int sequence_id() const { return sequence_id_; }
// Set the asynchronous task id
void set_sequence_id(int value) { sequence_id_ = value; }
// Get the status of the call
bool return_status() const { return return_status_; }
// Set the status of the call
void set_return_status(bool value) { return_status_ = value; }
// Get the MountError for applicable calls (Mount, MountGuest)
MountError return_code() const { return return_code_; }
// Set the MountError for applicable calls (Mount, MountGuest)
void set_return_code(MountError value) { return_code_ = value; }
scoped_refptr<Mount> mount() const { return mount_; }
void set_mount(const scoped_refptr<Mount>& value) { mount_ = value; }
bool pkcs11_init() const { return pkcs11_init_; }
void set_pkcs11_init(bool value) { pkcs11_init_ = value; }
bool guest() const { return guest_; }
void set_guest(bool value) { guest_ = value; }
const SecureBlob* return_data() const { return return_data_.get(); }
void set_return_data(const SecureBlob& data) {
return_data_.reset(new SecureBlob(data.begin(), data.end()));
MountTaskResult& operator=(const MountTaskResult& rhs) {
sequence_id_ = rhs.sequence_id_;
return_status_ = rhs.return_status_;
return_code_ = rhs.return_code_;
if (rhs.return_data())
event_name_ = rhs.event_name_;
mount_ = rhs.mount_;
pkcs11_init_ = rhs.pkcs11_init_;
guest_ = rhs.guest_;
return *this;
virtual const char* GetEventName() const { return event_name_; }
int sequence_id_;
bool return_status_;
MountError return_code_;
std::unique_ptr<SecureBlob> return_data_;
const char* event_name_;
scoped_refptr<Mount> mount_;
bool pkcs11_init_;
bool guest_;
class MountTaskObserver : public base::CheckedObserver {
MountTaskObserver() {}
virtual ~MountTaskObserver() {}
// Called by the MountTask when the task is complete. If this returns true,
// the MountTaskObserver will be freed by the MountTask.
virtual bool MountTaskObserve(const MountTaskResult& result) = 0;
class MountTask : public base::RefCountedThreadSafe<MountTask> {
MountTask(MountTaskObserver* observer,
Mount* mount,
const Credentials& credentials,
int sequence_id);
MountTask(MountTaskObserver* observer, Mount* mount, int sequence_id);
MountTask(const MountTask&) = delete;
MountTask& operator=(const MountTask&) = delete;
virtual ~MountTask();
// Run is called by the worker thread when this task is being processed
virtual void Run() { Notify(); }
// Allow cancellation to be sent from the main thread. This must be checked
// in each inherited Run().
virtual void Cancel() { cancel_flag_.Set(); }
// Indicate if cancellation was requested.
virtual bool IsCanceled() { return cancel_flag_.IsSet(); }
// Gets the asynchronous call id of this task
int sequence_id() { return sequence_id_; }
// Returns the mount this task is for.
// TODO(wad) Figure out a better way. Queue per Mount?
scoped_refptr<Mount> mount() { return mount_; }
void set_mount(const scoped_refptr<Mount>& mount) {
mount_ = mount;
void set_credentials(const Credentials& credentials) {
credentials_ = credentials;
// Gets the MountTaskResult for this task
MountTaskResult* result() { return result_; }
// Sets the MountTaskResult for this task
void set_result(MountTaskResult* result) {
result_ = result;
// Sets the event to be signaled when the event is completed
void set_complete_event(base::WaitableEvent* value) {
complete_event_ = value;
// Notify implements the default behavior when this task is complete
void Notify();
// The Mount instance that does the actual work
scoped_refptr<Mount> mount_;
// The Credentials associated with this task
Credentials credentials_;
// The asychronous call id for this task
int sequence_id_;
// Checked before all Run() calls to cancel.
base::AtomicFlag cancel_flag_;
// Signal will call Signal on the completion event if it is set
void Signal();
// The MountTaskObserver to be notified when this task is complete
MountTaskObserver* observer_;
// The default instance of MountTaskResult to use if it is not set by the
// caller
std::unique_ptr<MountTaskResult> default_result_;
// The actual instance of MountTaskResult to use
MountTaskResult* result_;
// The completion event to signal when this task is complete
base::WaitableEvent* complete_event_;
} // namespace cryptohome