chromium/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.h

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_SCREENSHOT_JOB_H_
#define CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_SCREENSHOT_JOB_H_

#include <stddef.h>

#include <map>
#include <memory>
#include <string>
#include <utility>

#include "base/functional/callback.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/task/task_runner.h"
#include "chrome/browser/ash/policy/uploading/upload_job.h"
#include "components/policy/core/common/remote_commands/remote_command_job.h"
#include "ui/snapshot/snapshot.h"
#include "url/gurl.h"

namespace policy {

// The first element represents screen index, the second presents the PNG data.
using ScreenshotData = std::pair<size_t, scoped_refptr<base::RefCountedMemory>>;

using OnScreenshotTakenCallback =
    base::OnceCallback<void(scoped_refptr<base::RefCountedMemory>)>;

// This class implements a RemoteCommandJob that captures a screenshot from
// each attached screen and uploads the collected PNG data using UploadJob to
// the url specified in the "fileUploadUrl" field of the CommandPayload. Only
// one instance of this command will be running at a time. The
// RemoteCommandsQueue owns all instances of this class.
class DeviceCommandScreenshotJob : public RemoteCommandJob,
                                   public UploadJob::Delegate {
 public:
  static const char kUploadUrlFieldName[];
  // When the screenshot command terminates, the result payload that gets sent
  // to the server is populated with one of the following result codes. These
  // are exposed publicly here since DeviceCommandScreenshotTest uses them.
  enum ResultCode {
    // Successfully uploaded screenshots.
    SUCCESS = 0,

    // Aborted screenshot acquisition due to user input having been entered.
    FAILURE_USER_INPUT = 1,

    // Failed to acquire screenshots, e.g. no attached screens.
    FAILURE_SCREENSHOT_ACQUISITION = 2,

    // Failed to authenticate to the remote server.
    FAILURE_AUTHENTICATION = 3,

    // Failed due to an internal server error.
    FAILURE_SERVER = 4,

    // Failed due to a client-side error.
    FAILURE_CLIENT = 5,

    // Failed due to an invalid upload url.
    FAILURE_INVALID_URL = 6
  };

  // A delegate interface used by DeviceCommandScreenshotJob to retrieve its
  // dependencies.
  class Delegate {
   public:
    virtual ~Delegate() = default;

    // Returns true if screenshots are allowed in this session. Returns false
    // if the current session is not an auto-launched kiosk session, or there
    // have been certain types of user input that may result in leaking private
    // information.
    virtual bool IsScreenshotAllowed() = 0;

    // Acquires a snapshot of |source_rect| in |window| and invokes |callback|
    // with the PNG data. The passed-in callback will not be invoked after the
    // delegate has been destroyed. See e.g. ScreenshotDelegate.
    virtual void TakeSnapshot(gfx::NativeWindow window,
                              const gfx::Rect& source_rect,
                              OnScreenshotTakenCallback callback) = 0;

    // Creates a new fully configured instance of an UploadJob. This method
    // may be called any number of times.
    virtual std::unique_ptr<UploadJob> CreateUploadJob(
        const GURL&,
        UploadJob::Delegate*) = 0;
  };

  explicit DeviceCommandScreenshotJob(
      std::unique_ptr<Delegate> screenshot_delegate);

  DeviceCommandScreenshotJob(const DeviceCommandScreenshotJob&) = delete;
  DeviceCommandScreenshotJob& operator=(const DeviceCommandScreenshotJob&) =
      delete;

  ~DeviceCommandScreenshotJob() override;

  // RemoteCommandJob:
  enterprise_management::RemoteCommand_Type GetType() const override;

 private:
  class Payload;

  // UploadJob::Delegate:
  void OnSuccess() override;
  void OnFailure(UploadJob::ErrorCode error_code) override;

  // RemoteCommandJob:
  bool ParseCommandPayload(const std::string& command_payload) override;
  void RunImpl(CallbackWithResult result_callback) override;
  void TerminateImpl() override;

  // Posts `StartScreenshotUpload` job on |task_runner|.
  void OnScreenshotsReady(scoped_refptr<base::TaskRunner> task_runner,
                          std::vector<ScreenshotData> upload_data);

  void StartScreenshotUpload(std::vector<ScreenshotData> upload_data);

  void ReportResult(ResultType result_type, ResultCode result_code);

  // The URL to which the POST request should be directed.
  GURL upload_url_;

  // The callback that will be called when the screenshot was successfully
  // uploaded or when the command has failed.
  CallbackWithResult result_callback_;

  // The Delegate is used to acquire screenshots and create UploadJobs.
  std::unique_ptr<Delegate> screenshot_delegate_;

  // The upload job instance that will upload the screenshots.
  std::unique_ptr<UploadJob> upload_job_;

  base::WeakPtrFactory<DeviceCommandScreenshotJob> weak_ptr_factory_{this};
};

}  // namespace policy

#endif  // CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_SCREENSHOT_JOB_H_