Chromium 中chrome.downloads扩展接口c++

一、前端chrome.downloads

使用 chrome.downloads API 以编程方式启动、监控、操作和搜索下载内容。

权限

downloads

您必须在扩展程序清单中声明 "downloads" 权限,才能使用此 API。

{
  "name": "My extension",
  ...
  "permissions": [
    "downloads"
  ],
}

示例

您可以在 examples/api/downloads 中找到使用 chrome.downloads API 的简单示例 目录。如需获取其他示例以及查看源代码方面的帮助,请参阅示例

chrome.downloads  |  API  |  Chrome for Developers (google.cn)

二、downloads.idl接口定义:chrome\common\extensions\api\downloads.idl

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

// Use the <code>chrome.downloads</code> API to programmatically initiate,
// monitor, manipulate, and search for downloads.
[permissions=downloads]
namespace downloads {
  [inline_doc] dictionary HeaderNameValuePair {
    // Name of the HTTP header.
    DOMString name;

    // Value of the HTTP header.
    DOMString value;
  };

  // <dl><dt>uniquify</dt>
  //     <dd>To avoid duplication, the <code>filename</code> is changed to
  //     include a counter before the filename extension.</dd>
  //     <dt>overwrite</dt>
  //     <dd>The existing file will be overwritten with the new file.</dd>
  //     <dt>prompt</dt>
  //     <dd>The user will be prompted with a file chooser dialog.</dd>
  // </dl>
  enum FilenameConflictAction {uniquify, overwrite, prompt};

  [inline_doc] dictionary FilenameSuggestion {
    // The $(ref:DownloadItem)'s new target $(ref:DownloadItem.filename), as a path
    // relative to the user's default Downloads directory, possibly containing
    // subdirectories. Absolute paths, empty paths, and paths containing
    // back-references ".." will be ignored. <code>filename</code> is ignored if
    // there are any $(ref:onDeterminingFilename) listeners registered by any
    // extensions.
    DOMString filename;

    // The action to take if <code>filename</code> already exists.
    FilenameConflictAction? conflictAction;
  };

  [inline_doc] enum HttpMethod {GET, POST};

  enum InterruptReason {
    FILE_FAILED,
    FILE_ACCESS_DENIED,
    FILE_NO_SPACE,
    FILE_NAME_TOO_LONG,
    FILE_TOO_LARGE,
    FILE_VIRUS_INFECTED,
    FILE_TRANSIENT_ERROR,
    FILE_BLOCKED,
    FILE_SECURITY_CHECK_FAILED,
    FILE_TOO_SHORT,
    FILE_HASH_MISMATCH,
    FILE_SAME_AS_SOURCE,
    NETWORK_FAILED,
    NETWORK_TIMEOUT,
    NETWORK_DISCONNECTED,
    NETWORK_SERVER_DOWN,
    NETWORK_INVALID_REQUEST,
    SERVER_FAILED,
    SERVER_NO_RANGE,
    SERVER_BAD_CONTENT,
    SERVER_UNAUTHORIZED,
    SERVER_CERT_PROBLEM,
    SERVER_FORBIDDEN,
    SERVER_UNREACHABLE,
    SERVER_CONTENT_LENGTH_MISMATCH,
    SERVER_CROSS_ORIGIN_REDIRECT,
    USER_CANCELED,
    USER_SHUTDOWN,
    CRASH};

  [inline_doc] dictionary DownloadOptions {
    // The URL to download.
    DOMString url;

    // A file path relative to the Downloads directory to contain the downloaded
    // file, possibly containing subdirectories. Absolute paths, empty paths,
    // and paths containing back-references ".." will cause an error.
    // $(ref:onDeterminingFilename) allows suggesting a filename after the file's
    // MIME type and a tentative filename have been determined.
    DOMString? filename;

    // The action to take if <code>filename</code> already exists.
    FilenameConflictAction? conflictAction;

    // Use a file-chooser to allow the user to select a filename regardless of
    // whether <code>filename</code> is set or already exists.
    boolean? saveAs;

    // The HTTP method to use if the URL uses the HTTP[S] protocol.
    HttpMethod? method;

    // Extra HTTP headers to send with the request if the URL uses the HTTP[s]
    // protocol. Each header is represented as a dictionary containing the keys
    // <code>name</code> and either <code>value</code> or
    // <code>binaryValue</code>, restricted to those allowed by XMLHttpRequest.
    HeaderNameValuePair[]? headers;

    // Post body.
    DOMString? body;
  };

  // <dl><dt>file</dt>
  //     <dd>The download's filename is suspicious.</dd>
  //     <dt>url</dt>
  //     <dd>The download's URL is known to be malicious.</dd>
  //     <dt>content</dt>
  //     <dd>The downloaded file is known to be malicious.</dd>
  //     <dt>uncommon</dt>
  //     <dd>The download's URL is not commonly downloaded and could be
  //     dangerous.</dd>
  //     <dt>host</dt>
  //     <dd>The download came from a host known to distribute malicious
  //     binaries and is likely dangerous.</dd>
  //     <dt>unwanted</dt>
  //     <dd>The download is potentially unwanted or unsafe. E.g. it could make
  //     changes to browser or computer settings.</dd>
  //     <dt>safe</dt>
  //     <dd>The download presents no known danger to the user's computer.</dd>
  //     <dt>accepted</dt>
  //     <dd>The user has accepted the dangerous download.</dd>
  // </dl>
  enum DangerType {
    file,
    url,
    content,
    uncommon,
    host,
    unwanted,
    safe,
    accepted,
    allowlistedByPolicy,
    asyncScanning,
    asyncLocalPasswordScanning,
    passwordProtected,
    blockedTooLarge,
    sensitiveContentWarning,
    sensitiveContentBlock,
    unsupportedFileType,
    deepScannedFailed,
    deepScannedSafe,
    deepScannedOpenedDangerous,
    promptForScanning,
    promptForLocalPasswordScanning,
    accountCompromise
  };

  // <dl><dt>in_progress</dt>
  //     <dd>The download is currently receiving data from the server.</dd>
  //     <dt>interrupted</dt>
  //     <dd>An error broke the connection with the file host.</dd>
  //     <dt>complete</dt>
  //     <dd>The download completed successfully.</dd>
  // </dl>
  enum State {in_progress, interrupted, complete};

  // The state of the process of downloading a file.
  dictionary DownloadItem {
    // An identifier that is persistent across browser sessions.
    long id;

    // The absolute URL that this download initiated from, before any
    // redirects.
    DOMString url;

    // The absolute URL that this download is being made from, after all
    // redirects.
    DOMString finalUrl;

    // Absolute URL.
    DOMString referrer;

    // Absolute local path.
    DOMString filename;

    // False if this download is recorded in the history, true if it is not
    // recorded.
    boolean incognito;

    // Indication of whether this download is thought to be safe or known to be
    // suspicious.
    DangerType danger;

    // The file's MIME type.
    DOMString mime;

    // The time when the download began in ISO 8601 format. May be passed
    // directly to the Date constructor: <code>chrome.downloads.search({},
    // function(items){items.forEach(function(item){console.log(new
    // Date(item.startTime))})})</code>
    DOMString startTime;

    // The time when the download ended in ISO 8601 format. May be passed
    // directly to the Date constructor: <code>chrome.downloads.search({},
    // function(items){items.forEach(function(item){if (item.endTime)
    // console.log(new Date(item.endTime))})})</code>
    DOMString? endTime;

    // Estimated time when the download will complete in ISO 8601 format. May be
    // passed directly to the Date constructor:
    // <code>chrome.downloads.search({},
    // function(items){items.forEach(function(item){if (item.estimatedEndTime)
    // console.log(new Date(item.estimatedEndTime))})})</code>
    DOMString? estimatedEndTime;

    // Indicates whether the download is progressing, interrupted, or complete.
    State state;

    // True if the download has stopped reading data from the host, but kept the
    // connection open.
    boolean paused;

    // True if the download is in progress and paused, or else if it is
    // interrupted and can be resumed starting from where it was interrupted.
    boolean canResume;

    // Why the download was interrupted. Several kinds of HTTP errors may be
    // grouped under one of the errors beginning with <code>SERVER_</code>.
    // Errors relating to the network begin with <code>NETWORK_</code>, errors
    // relating to the process of writing the file to the file system begin with
    // <code>FILE_</code>, and interruptions initiated by the user begin with
    // <code>USER_</code>.
    InterruptReason? error;

    // Number of bytes received so far from the host, without considering file
    // compression.
    double bytesReceived;

    // Number of bytes in the whole file, without considering file compression,
    // or -1 if unknown.
    double totalBytes;

    // Number of bytes in the whole file post-decompression, or -1 if unknown.
    double fileSize;

    // Whether the downloaded file still exists. This information may be out of
    // date because Chrome does not automatically watch for file removal. Call
    // $(ref:search)() in order to trigger the check for file existence. When the
    // existence check completes, if the file has been deleted, then an
    // $(ref:onChanged) event will fire. Note that $(ref:search)() does not wait
    // for the existence check to finish before returning, so results from
    // $(ref:search)() may not accurately reflect the file system. Also,
    // $(ref:search)() may be called as often as necessary, but will not check for
    // file existence any more frequently than once every 10 seconds.
    boolean exists;

    // The identifier for the extension that initiated this download if this
    // download was initiated by an extension. Does not change once it is set.
    DOMString? byExtensionId;

    // The localized name of the extension that initiated this download if this
    // download was initiated by an extension. May change if the extension
    // changes its name or if the user changes their locale.
    DOMString? byExtensionName;
  };

  [inline_doc] dictionary DownloadQuery {
    // This array of search terms limits results to $(ref:DownloadItem) whose
    // <code>filename</code> or <code>url</code> or <code>finalUrl</code>
    // contain all of the search terms that do not begin with a dash '-' and
    // none of the search terms that do begin with a dash.
    DOMString[]? query;

    // Limits results to $(ref:DownloadItem) that
    // started before the given ms since the epoch.
    DOMString? startedBefore;

    // Limits results to $(ref:DownloadItem) that
    // started after the given ms since the epoch.
    DOMString? startedAfter;

    // Limits results to $(ref:DownloadItem) that ended before the given ms since the
    // epoch.
    DOMString? endedBefore;

    // Limits results to $(ref:DownloadItem) that ended after the given ms since the
    // epoch.
    DOMString? endedAfter;

    // Limits results to $(ref:DownloadItem) whose
    // <code>totalBytes</code> is greater than the given integer.
    double? totalBytesGreater;

    // Limits results to $(ref:DownloadItem) whose
    // <code>totalBytes</code> is less than the given integer.
    double? totalBytesLess;

    // Limits results to $(ref:DownloadItem) whose
    // <code>filename</code> matches the given regular expression.
    DOMString? filenameRegex;

    // Limits results to $(ref:DownloadItem) whose
    // <code>url</code> matches the given regular expression.
    DOMString? urlRegex;

    // Limits results to $(ref:DownloadItem) whose
    // <code>finalUrl</code> matches the given regular expression.
    DOMString? finalUrlRegex;

    // The maximum number of matching $(ref:DownloadItem) returned. Defaults to
    // 1000. Set to 0 in order to return all matching $(ref:DownloadItem). See
    // $(ref:search) for how to page through results.
    long? limit;

    // Set elements of this array to $(ref:DownloadItem) properties in order to
    // sort search results. For example, setting
    // <code>orderBy=['startTime']</code> sorts the $(ref:DownloadItem) by their
    // start time in ascending order. To specify descending order, prefix with a
    // hyphen: '-startTime'.
    DOMString[]? orderBy;

    // The <code>id</code> of the $(ref:DownloadItem) to query.
    long? id;

    // The absolute URL that this download initiated from, before any
    // redirects.
    DOMString? url;

    // The absolute URL that this download is being made from, after all
    // redirects.
    DOMString? finalUrl;

    // Absolute local path.
    DOMString? filename;

    // Indication of whether this download is thought to be safe or known to be
    // suspicious.
    DangerType? danger;

    // The file's MIME type.
    DOMString? mime;

    // The time when the download began in ISO 8601 format.
    DOMString? startTime;

    // The time when the download ended in ISO 8601 format.
    DOMString? endTime;

    // Indicates whether the download is progressing, interrupted, or complete.
    State? state;

    // True if the download has stopped reading data from the host, but kept the
    // connection open.
    boolean? paused;

    // Why a download was interrupted.
    InterruptReason? error;

    // Number of bytes received so far from the host, without considering file
    // compression.
    double? bytesReceived;

    // Number of bytes in the whole file, without considering file compression,
    // or -1 if unknown.
    double? totalBytes;

    // Number of bytes in the whole file post-decompression, or -1 if unknown.
    double? fileSize;

    // Whether the downloaded file exists;
    boolean? exists;
  };

  dictionary StringDelta {
    DOMString? previous;
    DOMString? current;
  };

  dictionary DoubleDelta {
    double? previous;
    double? current;
  };

  dictionary BooleanDelta {
    boolean? previous;
    boolean? current;
  };

  // Encapsulates a change in a DownloadItem.
  [inline_doc] dictionary DownloadDelta {
    // The <code>id</code> of the $(ref:DownloadItem)
    // that changed.
    long id;

    // The change in <code>url</code>, if any.
    StringDelta? url;

    // The change in <code>finalUrl</code>, if any.
    StringDelta? finalUrl;

    // The change in <code>filename</code>, if any.
    StringDelta? filename;

    // The change in <code>danger</code>, if any.
    StringDelta? danger;

    // The change in <code>mime</code>, if any.
    StringDelta? mime;

    // The change in <code>startTime</code>, if any.
    StringDelta? startTime;

    // The change in <code>endTime</code>, if any.
    StringDelta? endTime;

    // The change in <code>state</code>, if any.
    StringDelta? state;

    // The change in <code>canResume</code>, if any.
    BooleanDelta? canResume;

    // The change in <code>paused</code>, if any.
    BooleanDelta? paused;

    // The change in <code>error</code>, if any.
    StringDelta? error;

    // The change in <code>totalBytes</code>, if any.
    DoubleDelta? totalBytes;

    // The change in <code>fileSize</code>, if any.
    DoubleDelta? fileSize;

    // The change in <code>exists</code>, if any.
    BooleanDelta? exists;
  };

  [inline_doc] dictionary GetFileIconOptions {
    // The size of the returned icon. The icon will be square with dimensions
    // size * size pixels. The default and largest size for the icon is 32x32
    // pixels. The only supported sizes are 16 and 32. It is an error to specify
    // any other size.
    [legalValues=(16,32)] long? size;
  };

  // Encapsulates a change in the download UI.
  [inline_doc] dictionary UiOptions {
    // Enable or disable the download UI.
    boolean enabled;
  };

  callback DownloadCallback = void(long downloadId);
  callback SearchCallback = void(DownloadItem[] results);
  callback EraseCallback = void(long[] erasedIds);
  callback NullCallback = void();
  callback GetFileIconCallback = void(optional DOMString iconURL);
  callback SuggestFilenameCallback = void(
    optional FilenameSuggestion suggestion);

  interface Functions {
    // Download a URL. If the URL uses the HTTP[S] protocol, then the request
    // will include all cookies currently set for its hostname. If both
    // <code>filename</code> and <code>saveAs</code> are specified, then the
    // Save As dialog will be displayed, pre-populated with the specified
    // <code>filename</code>. If the download started successfully,
    // <code>callback</code> will be called with the new $(ref:DownloadItem)'s
    // <code>downloadId</code>. If there was an error starting the download,
    // then <code>callback</code> will be called with
    // <code>downloadId=undefined</code> and $(ref:runtime.lastError) will contain
    // a descriptive string. The error strings are not guaranteed to remain
    // backwards compatible between releases. Extensions must not parse it.
    // |options|: What to download and how.
    // |callback|: Called with the id of the new $(ref:DownloadItem).
    [supportsPromises] static void download(
        DownloadOptions options,
        optional DownloadCallback callback);

    // Find $(ref:DownloadItem). Set <code>query</code> to the empty object to get
    // all $(ref:DownloadItem). To get a specific $(ref:DownloadItem), set only the
    // <code>id</code> field. To page through a large number of items, set
    // <code>orderBy: ['-startTime']</code>, set <code>limit</code> to the
    // number of items per page, and set <code>startedAfter</code> to the
    // <code>startTime</code> of the last item from the last page.
    [supportsPromises] static void search(DownloadQuery query,
                                          SearchCallback callback);

    // Pause the download. If the request was successful the download is in a
    // paused state. Otherwise $(ref:runtime.lastError) contains an error message.
    // The request will fail if the download is not active.
    // |downloadId|: The id of the download to pause.
    // |callback|: Called when the pause request is completed.
    [supportsPromises] static void pause(long downloadId,
                                         optional NullCallback callback);

    // Resume a paused download. If the request was successful the download is
    // in progress and unpaused. Otherwise $(ref:runtime.lastError) contains an
    // error message. The request will fail if the download is not active.
    // |downloadId|: The id of the download to resume.
    // |callback|: Called when the resume request is completed.
    [supportsPromises] static void resume(long downloadId,
                                          optional NullCallback callback);

    // Cancel a download. When <code>callback</code> is run, the download is
    // cancelled, completed, interrupted or doesn't exist anymore.
    // |downloadId|: The id of the download to cancel.
    // |callback|: Called when the cancel request is completed.
    [supportsPromises] static void cancel(long downloadId,
                                          optional NullCallback callback);

    // Retrieve an icon for the specified download. For new downloads, file
    // icons are available after the $(ref:onCreated) event has been received. The
    // image returned by this function while a download is in progress may be
    // different from the image returned after the download is complete. Icon
    // retrieval is done by querying the underlying operating system or toolkit
    // depending on the platform. The icon that is returned will therefore
    // depend on a number of factors including state of the download, platform,
    // registered file types and visual theme. If a file icon cannot be
    // determined, $(ref:runtime.lastError) will contain an error message.
    // |downloadId|: The identifier for the download.
    // |callback|: A URL to an image that represents the download.
    [supportsPromises] static void getFileIcon(
        long downloadId,
        optional GetFileIconOptions options,
        GetFileIconCallback callback);

    // Open the downloaded file now if the $(ref:DownloadItem) is complete;
    // otherwise returns an error through $(ref:runtime.lastError). Requires the
    // <code>"downloads.open"</code> permission in addition to the
    // <code>"downloads"</code> permission. An $(ref:onChanged) event will fire
    // when the item is opened for the first time.
    // |downloadId|: The identifier for the downloaded file.
    static void open(long downloadId);

    // Show the downloaded file in its folder in a file manager.
    // |downloadId|: The identifier for the downloaded file.
    static void show(long downloadId);

    // Show the default Downloads folder in a file manager.
    static void showDefaultFolder();

    // Erase matching $(ref:DownloadItem) from history without deleting the
    // downloaded file. An $(ref:onErased) event will fire for each
    // $(ref:DownloadItem) that matches <code>query</code>, then
    // <code>callback</code> will be called.
    [supportsPromises] static void erase(DownloadQuery query,
                                         optional EraseCallback callback);

    // Remove the downloaded file if it exists and the $(ref:DownloadItem) is
    // complete; otherwise return an error through $(ref:runtime.lastError).
    [supportsPromises] static void removeFile(long downloadId,
                                              optional NullCallback callback);

    // Prompt the user to accept a dangerous download. Can only be called from a
    // visible context (tab, window, or page/browser action popup). Does not
    // automatically accept dangerous downloads. If the download is accepted,
    // then an $(ref:onChanged) event will fire, otherwise nothing will happen.
    // When all the data is fetched into a temporary file and either the
    // download is not dangerous or the danger has been accepted, then the
    // temporary file is renamed to the target filename, the |state| changes to
    // 'complete', and $(ref:onChanged) fires.
    // |downloadId|: The identifier for the $(ref:DownloadItem).
    // |callback|: Called when the danger prompt dialog closes.
    [supportsPromises] static void acceptDanger(long downloadId,
                                                optional NullCallback callback);

    // Enable or disable the gray shelf at the bottom of every window associated
    // with the current browser profile. The shelf will be disabled as long as
    // at least one extension has disabled it. Enabling the shelf while at least
    // one other extension has disabled it will return an error through
    // $(ref:runtime.lastError). Requires the <code>"downloads.shelf"</code>
    // permission in addition to the <code>"downloads"</code> permission.
    [deprecated="Use $(ref:setUiOptions) instead."]
    static void setShelfEnabled(boolean enabled);

    // Change the download UI of every window associated with the current
    // browser profile. As long as at least one extension has set
    // $(ref:UiOptions.enabled) to false, the download UI will be hidden.
    // Setting $(ref:UiOptions.enabled) to true while at least one other
    // extension has disabled it will return an error through
    // $(ref:runtime.lastError). Requires the <code>"downloads.ui"</code>
    // permission in addition to the <code>"downloads"</code> permission.
    // |options|: Encapsulate a change to the download UI.
    // |callback|: Called when the UI update is completed.
    [supportsPromises] static void setUiOptions(UiOptions options,
                                                optional NullCallback callback);
  };

  interface Events {
    // This event fires with the $(ref:DownloadItem) object when a download
    // begins.
    static void onCreated(DownloadItem downloadItem);

    // Fires with the <code>downloadId</code> when a download is erased from
    // history.
    // |downloadId|: The <code>id</code> of the $(ref:DownloadItem) that was
    // erased.
    static void onErased(long downloadId);

    // When any of a $(ref:DownloadItem)'s properties except
    // <code>bytesReceived</code> and <code>estimatedEndTime</code> changes,
    // this event fires with the <code>downloadId</code> and an object
    // containing the properties that changed.
    static void onChanged(DownloadDelta downloadDelta);

    // During the filename determination process, extensions will be given the
    // opportunity to override the target $(ref:DownloadItem.filename). Each
    // extension may not register more than one listener for this event. Each
    // listener must call <code>suggest</code> exactly once, either
    // synchronously or asynchronously. If the listener calls
    // <code>suggest</code> asynchronously, then it must return
    // <code>true</code>. If the listener neither calls <code>suggest</code>
    // synchronously nor returns <code>true</code>, then <code>suggest</code>
    // will be called automatically. The $(ref:DownloadItem) will not complete
    // until all listeners have called <code>suggest</code>. Listeners may call
    // <code>suggest</code> without any arguments in order to allow the download
    // to use <code>downloadItem.filename</code> for its filename, or pass a
    // <code>suggestion</code> object to <code>suggest</code> in order to
    // override the target filename. If more than one extension overrides the
    // filename, then the last extension installed whose listener passes a
    // <code>suggestion</code> object to <code>suggest</code> wins. In order to
    // avoid confusion regarding which extension will win, users should not
    // install extensions that may conflict. If the download is initiated by
    // $(ref:download) and the target filename is known before the MIME type and
    // tentative filename have been determined, pass <code>filename</code> to
    // $(ref:download) instead.
    [maxListeners=1] static void onDeterminingFilename(
        DownloadItem downloadItem, SuggestFilenameCallback suggest);
  };
};

downloads.idl生成的文件

// GENERATED FROM THE API DEFINITION IN
//   chrome/common/extensions/api/downloads.idl
// by tools/json_schema_compiler.

out\Debug\gen\chrome\common\extensions\api\downloads.h

out\Debug\gen\chrome\common\extensions\api\downloads.cc

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

// GENERATED FROM THE API DEFINITION IN
//   chrome/common/extensions/api/downloads.idl
// by tools/json_schema_compiler.
// DO NOT EDIT.

#ifndef CHROME_COMMON_EXTENSIONS_API_DOWNLOADS_H__
#define CHROME_COMMON_EXTENSIONS_API_DOWNLOADS_H__

#include <stdint.h>

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/values.h"
#include "base/strings/string_piece.h"


namespace extensions {
namespace api {
namespace downloads {

//
// Types
//

struct HeaderNameValuePair {
  HeaderNameValuePair();
  ~HeaderNameValuePair();
  HeaderNameValuePair(const HeaderNameValuePair&) = delete;
  HeaderNameValuePair& operator=(const HeaderNameValuePair&) = delete;
  HeaderNameValuePair(HeaderNameValuePair&& rhs) noexcept;
  HeaderNameValuePair& operator=(HeaderNameValuePair&& rhs) noexcept;

  // Populates a HeaderNameValuePair object from a base::Value& instance.
  // Returns whether |out| was successfully populated.
  static bool Populate(const base::Value& value, HeaderNameValuePair& out);

  // Populates a HeaderNameValuePair object from a Dict& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, HeaderNameValuePair& out);

  // Creates a deep copy of HeaderNameValuePair.
  HeaderNameValuePair Clone() const;

  // Creates a HeaderNameValuePair object from a base::Value::Dict, or nullopt
  // on failure.
  static std::optional<HeaderNameValuePair> FromValue(const base::Value::Dict& value);

  // Creates a HeaderNameValuePair object from a base::Value, or nullopt on
  // failure.
  static std::optional<HeaderNameValuePair> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisHeaderNameValuePair object.
  base::Value::Dict ToValue() const;

  // Name of the HTTP header.
  std::string name;

  // Value of the HTTP header.
  std::string value;

};

// <dl><dt>uniquify</dt>     <dd>To avoid duplication, the <code>filename</code>
// is changed to     include a counter before the filename extension.</dd>
// <dt>overwrite</dt>     <dd>The existing file will be overwritten with the new
// file.</dd>     <dt>prompt</dt>     <dd>The user will be prompted with a file
// chooser dialog.</dd> </dl>
enum class FilenameConflictAction {
  kNone = 0,
  kUniquify,
  kOverwrite,
  kPrompt,
  kMaxValue = kPrompt,
};


const char* ToString(FilenameConflictAction as_enum);
FilenameConflictAction ParseFilenameConflictAction(base::StringPiece as_string);
std::u16string GetFilenameConflictActionParseError(base::StringPiece as_string);

struct FilenameSuggestion {
  FilenameSuggestion();
  ~FilenameSuggestion();
  FilenameSuggestion(const FilenameSuggestion&) = delete;
  FilenameSuggestion& operator=(const FilenameSuggestion&) = delete;
  FilenameSuggestion(FilenameSuggestion&& rhs) noexcept;
  FilenameSuggestion& operator=(FilenameSuggestion&& rhs) noexcept;

  // Populates a FilenameSuggestion object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, FilenameSuggestion& out);

  // Populates a FilenameSuggestion object from a Dict& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, FilenameSuggestion& out);

  // Creates a deep copy of FilenameSuggestion.
  FilenameSuggestion Clone() const;

  // Creates a FilenameSuggestion object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<FilenameSuggestion> FromValue(const base::Value::Dict& value);

  // Creates a FilenameSuggestion object from a base::Value, or nullopt on
  // failure.
  static std::optional<FilenameSuggestion> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisFilenameSuggestion object.
  base::Value::Dict ToValue() const;

  // The $(ref:DownloadItem)'s new target $(ref:DownloadItem.filename), as a path
  // relative to the user's default Downloads directory, possibly containing
  // subdirectories. Absolute paths, empty paths, and paths containing
  // back-references ".." will be ignored. <code>filename</code> is ignored if
  // there are any $(ref:onDeterminingFilename) listeners registered by any
  // extensions.
  std::string filename;

  // The action to take if <code>filename</code> already exists.
  FilenameConflictAction conflict_action;

};

enum class HttpMethod {
  kNone = 0,
  kGet,
  kPost,
  kMaxValue = kPost,
};


const char* ToString(HttpMethod as_enum);
HttpMethod ParseHttpMethod(base::StringPiece as_string);
std::u16string GetHttpMethodParseError(base::StringPiece as_string);

enum class InterruptReason {
  kNone = 0,
  kFileFailed,
  kFileAccessDenied,
  kFileNoSpace,
  kFileNameTooLong,
  kFileTooLarge,
  kFileVirusInfected,
  kFileTransientError,
  kFileBlocked,
  kFileSecurityCheckFailed,
  kFileTooShort,
  kFileHashMismatch,
  kFileSameAsSource,
  kNetworkFailed,
  kNetworkTimeout,
  kNetworkDisconnected,
  kNetworkServerDown,
  kNetworkInvalidRequest,
  kServerFailed,
  kServerNoRange,
  kServerBadContent,
  kServerUnauthorized,
  kServerCertProblem,
  kServerForbidden,
  kServerUnreachable,
  kServerContentLengthMismatch,
  kServerCrossOriginRedirect,
  kUserCanceled,
  kUserShutdown,
  kCrash,
  kMaxValue = kCrash,
};


const char* ToString(InterruptReason as_enum);
InterruptReason ParseInterruptReason(base::StringPiece as_string);
std::u16string GetInterruptReasonParseError(base::StringPiece as_string);

struct DownloadOptions {
  DownloadOptions();
  ~DownloadOptions();
  DownloadOptions(const DownloadOptions&) = delete;
  DownloadOptions& operator=(const DownloadOptions&) = delete;
  DownloadOptions(DownloadOptions&& rhs) noexcept;
  DownloadOptions& operator=(DownloadOptions&& rhs) noexcept;

  // Populates a DownloadOptions object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, DownloadOptions& out);

  // Populates a DownloadOptions object from a Dict& instance. Returns whether
  // |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, DownloadOptions& out);

  // Creates a deep copy of DownloadOptions.
  DownloadOptions Clone() const;

  // Creates a DownloadOptions object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<DownloadOptions> FromValue(const base::Value::Dict& value);

  // Creates a DownloadOptions object from a base::Value, or nullopt on failure.
  static std::optional<DownloadOptions> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisDownloadOptions object.
  base::Value::Dict ToValue() const;

  // The URL to download.
  std::string url;

  // A file path relative to the Downloads directory to contain the downloaded
  // file, possibly containing subdirectories. Absolute paths, empty paths, and
  // paths containing back-references ".." will cause an error.
  // $(ref:onDeterminingFilename) allows suggesting a filename after the file's
  // MIME type and a tentative filename have been determined.
  std::optional<std::string> filename;

  // The action to take if <code>filename</code> already exists.
  FilenameConflictAction conflict_action;

  // Use a file-chooser to allow the user to select a filename regardless of
  // whether <code>filename</code> is set or already exists.
  std::optional<bool> save_as;

  // The HTTP method to use if the URL uses the HTTP[S] protocol.
  HttpMethod method;

  // Extra HTTP headers to send with the request if the URL uses the HTTP[s]
  // protocol. Each header is represented as a dictionary containing the keys
  // <code>name</code> and either <code>value</code> or <code>binaryValue</code>,
  // restricted to those allowed by XMLHttpRequest.
  std::optional<std::vector<HeaderNameValuePair>> headers;

  // Post body.
  std::optional<std::string> body;

};

// <dl><dt>file</dt>     <dd>The download's filename is suspicious.</dd>
// <dt>url</dt>     <dd>The download's URL is known to be malicious.</dd>
// <dt>content</dt>     <dd>The downloaded file is known to be malicious.</dd>
// <dt>uncommon</dt>     <dd>The download's URL is not commonly downloaded and
// could be     dangerous.</dd>     <dt>host</dt>     <dd>The download came from
// a host known to distribute malicious     binaries and is likely
// dangerous.</dd>     <dt>unwanted</dt>     <dd>The download is potentially
// unwanted or unsafe. E.g. it could make     changes to browser or computer
// settings.</dd>     <dt>safe</dt>     <dd>The download presents no known
// danger to the user's computer.</dd>     <dt>accepted</dt>     <dd>The user
// has accepted the dangerous download.</dd> </dl>
enum class DangerType {
  kNone = 0,
  kFile,
  kUrl,
  kContent,
  kUncommon,
  kHost,
  kUnwanted,
  kSafe,
  kAccepted,
  kAllowlistedByPolicy,
  kAsyncScanning,
  kAsyncLocalPasswordScanning,
  kPasswordProtected,
  kBlockedTooLarge,
  kSensitiveContentWarning,
  kSensitiveContentBlock,
  kUnsupportedFileType,
  kDeepScannedFailed,
  kDeepScannedSafe,
  kDeepScannedOpenedDangerous,
  kPromptForScanning,
  kPromptForLocalPasswordScanning,
  kAccountCompromise,
  kMaxValue = kAccountCompromise,
};


const char* ToString(DangerType as_enum);
DangerType ParseDangerType(base::StringPiece as_string);
std::u16string GetDangerTypeParseError(base::StringPiece as_string);

// <dl><dt>in_progress</dt>     <dd>The download is currently receiving data
// from the server.</dd>     <dt>interrupted</dt>     <dd>An error broke the
// connection with the file host.</dd>     <dt>complete</dt>     <dd>The
// download completed successfully.</dd> </dl>
enum class State {
  kNone = 0,
  kInProgress,
  kInterrupted,
  kComplete,
  kMaxValue = kComplete,
};


const char* ToString(State as_enum);
State ParseState(base::StringPiece as_string);
std::u16string GetStateParseError(base::StringPiece as_string);

struct DownloadItem {
  DownloadItem();
  ~DownloadItem();
  DownloadItem(const DownloadItem&) = delete;
  DownloadItem& operator=(const DownloadItem&) = delete;
  DownloadItem(DownloadItem&& rhs) noexcept;
  DownloadItem& operator=(DownloadItem&& rhs) noexcept;

  // Populates a DownloadItem object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, DownloadItem& out);

  // Populates a DownloadItem object from a Dict& instance. Returns whether
  // |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, DownloadItem& out);

  // Creates a deep copy of DownloadItem.
  DownloadItem Clone() const;

  // Creates a DownloadItem object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<DownloadItem> FromValue(const base::Value::Dict& value);

  // Creates a DownloadItem object from a base::Value, or nullopt on failure.
  static std::optional<DownloadItem> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisDownloadItem object.
  base::Value::Dict ToValue() const;

  // An identifier that is persistent across browser sessions.
  int id;

  // The absolute URL that this download initiated from, before any redirects.
  std::string url;

  // The absolute URL that this download is being made from, after all redirects.
  std::string final_url;

  // Absolute URL.
  std::string referrer;

  // Absolute local path.
  std::string filename;

  // False if this download is recorded in the history, true if it is not
  // recorded.
  bool incognito;

  // Indication of whether this download is thought to be safe or known to be
  // suspicious.
  DangerType danger;

  // The file's MIME type.
  std::string mime;

  // The time when the download began in ISO 8601 format. May be passed directly
  // to the Date constructor: <code>chrome.downloads.search({},
  // function(items){items.forEach(function(item){console.log(new
  // Date(item.startTime))})})</code>
  std::string start_time;

  // The time when the download ended in ISO 8601 format. May be passed directly
  // to the Date constructor: <code>chrome.downloads.search({},
  // function(items){items.forEach(function(item){if (item.endTime)
  // console.log(new Date(item.endTime))})})</code>
  std::optional<std::string> end_time;

  // Estimated time when the download will complete in ISO 8601 format. May be
  // passed directly to the Date constructor: <code>chrome.downloads.search({},
  // function(items){items.forEach(function(item){if (item.estimatedEndTime)
  // console.log(new Date(item.estimatedEndTime))})})</code>
  std::optional<std::string> estimated_end_time;

  // Indicates whether the download is progressing, interrupted, or complete.
  State state;

  // True if the download has stopped reading data from the host, but kept the
  // connection open.
  bool paused;

  // True if the download is in progress and paused, or else if it is interrupted
  // and can be resumed starting from where it was interrupted.
  bool can_resume;

  // Why the download was interrupted. Several kinds of HTTP errors may be grouped
  // under one of the errors beginning with <code>SERVER_</code>. Errors relating
  // to the network begin with <code>NETWORK_</code>, errors relating to the
  // process of writing the file to the file system begin with <code>FILE_</code>,
  // and interruptions initiated by the user begin with <code>USER_</code>.
  InterruptReason error;

  // Number of bytes received so far from the host, without considering file
  // compression.
  double bytes_received;

  // Number of bytes in the whole file, without considering file compression, or
  // -1 if unknown.
  double total_bytes;

  // Number of bytes in the whole file post-decompression, or -1 if unknown.
  double file_size;

  // Whether the downloaded file still exists. This information may be out of date
  // because Chrome does not automatically watch for file removal. Call
  // $(ref:search)() in order to trigger the check for file existence. When the
  // existence check completes, if the file has been deleted, then an
  // $(ref:onChanged) event will fire. Note that $(ref:search)() does not wait for
  // the existence check to finish before returning, so results from
  // $(ref:search)() may not accurately reflect the file system. Also,
  // $(ref:search)() may be called as often as necessary, but will not check for
  // file existence any more frequently than once every 10 seconds.
  bool exists;

  // The identifier for the extension that initiated this download if this
  // download was initiated by an extension. Does not change once it is set.
  std::optional<std::string> by_extension_id;

  // The localized name of the extension that initiated this download if this
  // download was initiated by an extension. May change if the extension changes
  // its name or if the user changes their locale.
  std::optional<std::string> by_extension_name;

};

struct DownloadQuery {
  DownloadQuery();
  ~DownloadQuery();
  DownloadQuery(const DownloadQuery&) = delete;
  DownloadQuery& operator=(const DownloadQuery&) = delete;
  DownloadQuery(DownloadQuery&& rhs) noexcept;
  DownloadQuery& operator=(DownloadQuery&& rhs) noexcept;

  // Populates a DownloadQuery object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, DownloadQuery& out);

  // Populates a DownloadQuery object from a Dict& instance. Returns whether
  // |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, DownloadQuery& out);

  // Creates a deep copy of DownloadQuery.
  DownloadQuery Clone() const;

  // Creates a DownloadQuery object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<DownloadQuery> FromValue(const base::Value::Dict& value);

  // Creates a DownloadQuery object from a base::Value, or nullopt on failure.
  static std::optional<DownloadQuery> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisDownloadQuery object.
  base::Value::Dict ToValue() const;

  // This array of search terms limits results to $(ref:DownloadItem) whose
  // <code>filename</code> or <code>url</code> or <code>finalUrl</code> contain
  // all of the search terms that do not begin with a dash '-' and none of the
  // search terms that do begin with a dash.
  std::optional<std::vector<std::string>> query;

  // Limits results to $(ref:DownloadItem) that started before the given ms since
  // the epoch.
  std::optional<std::string> started_before;

  // Limits results to $(ref:DownloadItem) that started after the given ms since
  // the epoch.
  std::optional<std::string> started_after;

  // Limits results to $(ref:DownloadItem) that ended before the given ms since
  // the epoch.
  std::optional<std::string> ended_before;

  // Limits results to $(ref:DownloadItem) that ended after the given ms since the
  // epoch.
  std::optional<std::string> ended_after;

  // Limits results to $(ref:DownloadItem) whose <code>totalBytes</code> is
  // greater than the given integer.
  std::optional<double> total_bytes_greater;

  // Limits results to $(ref:DownloadItem) whose <code>totalBytes</code> is less
  // than the given integer.
  std::optional<double> total_bytes_less;

  // Limits results to $(ref:DownloadItem) whose <code>filename</code> matches the
  // given regular expression.
  std::optional<std::string> filename_regex;

  // Limits results to $(ref:DownloadItem) whose <code>url</code> matches the
  // given regular expression.
  std::optional<std::string> url_regex;

  // Limits results to $(ref:DownloadItem) whose <code>finalUrl</code> matches the
  // given regular expression.
  std::optional<std::string> final_url_regex;

  // The maximum number of matching $(ref:DownloadItem) returned. Defaults to
  // 1000. Set to 0 in order to return all matching $(ref:DownloadItem). See
  // $(ref:search) for how to page through results.
  std::optional<int> limit;

  // Set elements of this array to $(ref:DownloadItem) properties in order to sort
  // search results. For example, setting <code>orderBy=['startTime']</code> sorts
  // the $(ref:DownloadItem) by their start time in ascending order. To specify
  // descending order, prefix with a hyphen: '-startTime'.
  std::optional<std::vector<std::string>> order_by;

  // The <code>id</code> of the $(ref:DownloadItem) to query.
  std::optional<int> id;

  // The absolute URL that this download initiated from, before any redirects.
  std::optional<std::string> url;

  // The absolute URL that this download is being made from, after all redirects.
  std::optional<std::string> final_url;

  // Absolute local path.
  std::optional<std::string> filename;

  // Indication of whether this download is thought to be safe or known to be
  // suspicious.
  DangerType danger;

  // The file's MIME type.
  std::optional<std::string> mime;

  // The time when the download began in ISO 8601 format.
  std::optional<std::string> start_time;

  // The time when the download ended in ISO 8601 format.
  std::optional<std::string> end_time;

  // Indicates whether the download is progressing, interrupted, or complete.
  State state;

  // True if the download has stopped reading data from the host, but kept the
  // connection open.
  std::optional<bool> paused;

  // Why a download was interrupted.
  InterruptReason error;

  // Number of bytes received so far from the host, without considering file
  // compression.
  std::optional<double> bytes_received;

  // Number of bytes in the whole file, without considering file compression, or
  // -1 if unknown.
  std::optional<double> total_bytes;

  // Number of bytes in the whole file post-decompression, or -1 if unknown.
  std::optional<double> file_size;

  // Whether the downloaded file exists;
  std::optional<bool> exists;

};

struct StringDelta {
  StringDelta();
  ~StringDelta();
  StringDelta(const StringDelta&) = delete;
  StringDelta& operator=(const StringDelta&) = delete;
  StringDelta(StringDelta&& rhs) noexcept;
  StringDelta& operator=(StringDelta&& rhs) noexcept;

  // Populates a StringDelta object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, StringDelta& out);

  // Populates a StringDelta object from a Dict& instance. Returns whether |out|
  // was successfully populated.
  static bool Populate(const base::Value::Dict& value, StringDelta& out);

  // Creates a deep copy of StringDelta.
  StringDelta Clone() const;

  // Creates a StringDelta object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<StringDelta> FromValue(const base::Value::Dict& value);

  // Creates a StringDelta object from a base::Value, or nullopt on failure.
  static std::optional<StringDelta> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisStringDelta object.
  base::Value::Dict ToValue() const;

  std::optional<std::string> previous;

  std::optional<std::string> current;

};

struct DoubleDelta {
  DoubleDelta();
  ~DoubleDelta();
  DoubleDelta(const DoubleDelta&) = delete;
  DoubleDelta& operator=(const DoubleDelta&) = delete;
  DoubleDelta(DoubleDelta&& rhs) noexcept;
  DoubleDelta& operator=(DoubleDelta&& rhs) noexcept;

  // Populates a DoubleDelta object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, DoubleDelta& out);

  // Populates a DoubleDelta object from a Dict& instance. Returns whether |out|
  // was successfully populated.
  static bool Populate(const base::Value::Dict& value, DoubleDelta& out);

  // Creates a deep copy of DoubleDelta.
  DoubleDelta Clone() const;

  // Creates a DoubleDelta object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<DoubleDelta> FromValue(const base::Value::Dict& value);

  // Creates a DoubleDelta object from a base::Value, or nullopt on failure.
  static std::optional<DoubleDelta> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisDoubleDelta object.
  base::Value::Dict ToValue() const;

  std::optional<double> previous;

  std::optional<double> current;

};

struct BooleanDelta {
  BooleanDelta();
  ~BooleanDelta();
  BooleanDelta(const BooleanDelta&) = delete;
  BooleanDelta& operator=(const BooleanDelta&) = delete;
  BooleanDelta(BooleanDelta&& rhs) noexcept;
  BooleanDelta& operator=(BooleanDelta&& rhs) noexcept;

  // Populates a BooleanDelta object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, BooleanDelta& out);

  // Populates a BooleanDelta object from a Dict& instance. Returns whether
  // |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, BooleanDelta& out);

  // Creates a deep copy of BooleanDelta.
  BooleanDelta Clone() const;

  // Creates a BooleanDelta object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<BooleanDelta> FromValue(const base::Value::Dict& value);

  // Creates a BooleanDelta object from a base::Value, or nullopt on failure.
  static std::optional<BooleanDelta> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisBooleanDelta object.
  base::Value::Dict ToValue() const;

  std::optional<bool> previous;

  std::optional<bool> current;

};

struct DownloadDelta {
  DownloadDelta();
  ~DownloadDelta();
  DownloadDelta(const DownloadDelta&) = delete;
  DownloadDelta& operator=(const DownloadDelta&) = delete;
  DownloadDelta(DownloadDelta&& rhs) noexcept;
  DownloadDelta& operator=(DownloadDelta&& rhs) noexcept;

  // Populates a DownloadDelta object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, DownloadDelta& out);

  // Populates a DownloadDelta object from a Dict& instance. Returns whether
  // |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, DownloadDelta& out);

  // Creates a deep copy of DownloadDelta.
  DownloadDelta Clone() const;

  // Creates a DownloadDelta object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<DownloadDelta> FromValue(const base::Value::Dict& value);

  // Creates a DownloadDelta object from a base::Value, or nullopt on failure.
  static std::optional<DownloadDelta> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisDownloadDelta object.
  base::Value::Dict ToValue() const;

  // The <code>id</code> of the $(ref:DownloadItem) that changed.
  int id;

  // The change in <code>url</code>, if any.
  std::optional<StringDelta> url;

  // The change in <code>finalUrl</code>, if any.
  std::optional<StringDelta> final_url;

  // The change in <code>filename</code>, if any.
  std::optional<StringDelta> filename;

  // The change in <code>danger</code>, if any.
  std::optional<StringDelta> danger;

  // The change in <code>mime</code>, if any.
  std::optional<StringDelta> mime;

  // The change in <code>startTime</code>, if any.
  std::optional<StringDelta> start_time;

  // The change in <code>endTime</code>, if any.
  std::optional<StringDelta> end_time;

  // The change in <code>state</code>, if any.
  std::optional<StringDelta> state;

  // The change in <code>canResume</code>, if any.
  std::optional<BooleanDelta> can_resume;

  // The change in <code>paused</code>, if any.
  std::optional<BooleanDelta> paused;

  // The change in <code>error</code>, if any.
  std::optional<StringDelta> error;

  // The change in <code>totalBytes</code>, if any.
  std::optional<DoubleDelta> total_bytes;

  // The change in <code>fileSize</code>, if any.
  std::optional<DoubleDelta> file_size;

  // The change in <code>exists</code>, if any.
  std::optional<BooleanDelta> exists;

};

struct GetFileIconOptions {
  GetFileIconOptions();
  ~GetFileIconOptions();
  GetFileIconOptions(const GetFileIconOptions&) = delete;
  GetFileIconOptions& operator=(const GetFileIconOptions&) = delete;
  GetFileIconOptions(GetFileIconOptions&& rhs) noexcept;
  GetFileIconOptions& operator=(GetFileIconOptions&& rhs) noexcept;

  // Populates a GetFileIconOptions object from a base::Value& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value& value, GetFileIconOptions& out);

  // Populates a GetFileIconOptions object from a Dict& instance. Returns
  // whether |out| was successfully populated.
  static bool Populate(const base::Value::Dict& value, GetFileIconOptions& out);

  // Creates a deep copy of GetFileIconOptions.
  GetFileIconOptions Clone() const;

  // Creates a GetFileIconOptions object from a base::Value::Dict, or nullopt on
  // failure.
  static std::optional<GetFileIconOptions> FromValue(const base::Value::Dict& value);

  // Creates a GetFileIconOptions object from a base::Value, or nullopt on
  // failure.
  static std::optional<GetFileIconOptions> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisGetFileIconOptions object.
  base::Value::Dict ToValue() const;

  // The size of the returned icon. The icon will be square with dimensions size *
  // size pixels. The default and largest size for the icon is 32x32 pixels. The
  // only supported sizes are 16 and 32. It is an error to specify any other size.
  std::optional<int> size;

};

struct UiOptions {
  UiOptions();
  ~UiOptions();
  UiOptions(const UiOptions&) = delete;
  UiOptions& operator=(const UiOptions&) = delete;
  UiOptions(UiOptions&& rhs) noexcept;
  UiOptions& operator=(UiOptions&& rhs) noexcept;

  // Populates a UiOptions object from a base::Value& instance. Returns whether
  // |out| was successfully populated.
  static bool Populate(const base::Value& value, UiOptions& out);

  // Populates a UiOptions object from a Dict& instance. Returns whether |out|
  // was successfully populated.
  static bool Populate(const base::Value::Dict& value, UiOptions& out);

  // Creates a deep copy of UiOptions.
  UiOptions Clone() const;

  // Creates a UiOptions object from a base::Value::Dict, or nullopt on failure.
  static std::optional<UiOptions> FromValue(const base::Value::Dict& value);

  // Creates a UiOptions object from a base::Value, or nullopt on failure.
  static std::optional<UiOptions> FromValue(const base::Value& value);

  // Returns a new base::Value::Dict representing the serialized form of
  // thisUiOptions object.
  base::Value::Dict ToValue() const;

  // Enable or disable the download UI.
  bool enabled;

};


//
// Functions
//

namespace Download {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // What to download and how.
  DownloadOptions options;


 private:
  Params();
};

namespace Results {

base::Value::List Create(int download_id);
}  // namespace Results

}  // namespace Download

namespace Search {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  DownloadQuery query;


 private:
  Params();
};

namespace Results {

base::Value::List Create(const std::vector<DownloadItem>& results);
}  // namespace Results

}  // namespace Search

namespace Pause {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // The id of the download to pause.
  int download_id;


 private:
  Params();
};

namespace Results {

base::Value::List Create();
}  // namespace Results

}  // namespace Pause

namespace Resume {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // The id of the download to resume.
  int download_id;


 private:
  Params();
};

namespace Results {

base::Value::List Create();
}  // namespace Results

}  // namespace Resume

namespace Cancel {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // The id of the download to cancel.
  int download_id;


 private:
  Params();
};

namespace Results {

base::Value::List Create();
}  // namespace Results

}  // namespace Cancel

namespace GetFileIcon {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // The identifier for the download.
  int download_id;

  std::optional<GetFileIconOptions> options;


 private:
  Params();
};

namespace Results {

base::Value::List Create(const std::string& icon_url);
}  // namespace Results

}  // namespace GetFileIcon

namespace Open {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // The identifier for the downloaded file.
  int download_id;


 private:
  Params();
};

}  // namespace Open

namespace Show {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // The identifier for the downloaded file.
  int download_id;


 private:
  Params();
};

}  // namespace Show

namespace ShowDefaultFolder {

}  // namespace ShowDefaultFolder

namespace Erase {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  DownloadQuery query;


 private:
  Params();
};

namespace Results {

base::Value::List Create(const std::vector<int>& erased_ids);
}  // namespace Results

}  // namespace Erase

namespace RemoveFile {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  int download_id;


 private:
  Params();
};

namespace Results {

base::Value::List Create();
}  // namespace Results

}  // namespace RemoveFile

namespace AcceptDanger {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // The identifier for the $(ref:DownloadItem).
  int download_id;


 private:
  Params();
};

namespace Results {

base::Value::List Create();
}  // namespace Results

}  // namespace AcceptDanger

namespace SetShelfEnabled {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  bool enabled;


 private:
  Params();
};

}  // namespace SetShelfEnabled

namespace SetUiOptions {

struct Params {
  static std::optional<Params> Create(const base::Value::List& args);
  Params(const Params&) = delete;
  Params& operator=(const Params&) = delete;
  Params(Params&& rhs) noexcept;
  Params& operator=(Params&& rhs) noexcept;
  ~Params();

  // Encapsulate a change to the download UI.
  UiOptions options;


 private:
  Params();
};

namespace Results {

base::Value::List Create();
}  // namespace Results

}  // namespace SetUiOptions

//
// Events
//

namespace OnCreated {

extern const char kEventName[];  // "downloads.onCreated"

base::Value::List Create(const DownloadItem& download_item);
}  // namespace OnCreated

namespace OnErased {

extern const char kEventName[];  // "downloads.onErased"

// The <code>id</code> of the $(ref:DownloadItem) that was erased.
base::Value::List Create(int download_id);
}  // namespace OnErased

namespace OnChanged {

extern const char kEventName[];  // "downloads.onChanged"

base::Value::List Create(const DownloadDelta& download_delta);
}  // namespace OnChanged

namespace OnDeterminingFilename {

extern const char kEventName[];  // "downloads.onDeterminingFilename"

base::Value::List Create(const DownloadItem& download_item);
}  // namespace OnDeterminingFilename

}  // namespace downloads
}  // namespace api
}  // namespace extensions

#endif  // CHROME_COMMON_EXTENSIONS_API_DOWNLOADS_H__

三、downloads.idl接口对应扩展调用

chrome\browser\extensions\api\downloads\downloads_api.h

chrome\browser\extensions\api\downloads\downloads_api.cc

// Copyright 2012 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_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_

#include <memory>
#include <set>
#include <string>

#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chrome/browser/download/download_danger_prompt.h"
#include "chrome/common/extensions/api/downloads.h"
#include "components/download/content/public/all_download_item_notifier.h"
#include "components/download/public/common/download_path_reservation_tracker.h"
#include "content/public/browser/download_manager.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/warning_set.h"

class DownloadFileIconExtractor;
class DownloadOpenPrompt;
class Profile;

// Functions in the chrome.downloads namespace facilitate
// controlling downloads from extensions. See the full API doc at
// http://goo.gl/6hO1n

namespace download_extension_errors {

// Errors that can be returned through chrome.runtime.lastError.message.
extern const char kEmptyFile[];
extern const char kFileAlreadyDeleted[];
extern const char kFileNotRemoved[];
extern const char kIconNotFound[];
extern const char kInvalidDangerType[];
extern const char kInvalidFilename[];
extern const char kInvalidFilter[];
extern const char kInvalidHeaderName[];
extern const char kInvalidHeaderValue[];
extern const char kInvalidHeaderUnsafe[];
extern const char kInvalidId[];
extern const char kInvalidOrderBy[];
extern const char kInvalidQueryLimit[];
extern const char kInvalidState[];
extern const char kInvalidURL[];
extern const char kInvisibleContext[];
extern const char kNotComplete[];
extern const char kNotDangerous[];
extern const char kNotInProgress[];
extern const char kNotResumable[];
extern const char kOpenPermission[];
extern const char kShelfDisabled[];
extern const char kShelfPermission[];
extern const char kTooManyListeners[];
extern const char kUiDisabled[];
extern const char kUiPermission[];
extern const char kUnexpectedDeterminer[];
extern const char kUserGesture[];

}  // namespace download_extension_errors

namespace extensions {

class DownloadedByExtension : public base::SupportsUserData::Data {
 public:
  static DownloadedByExtension* Get(download::DownloadItem* item);

  DownloadedByExtension(download::DownloadItem* item,
                        const std::string& id,
                        const std::string& name);

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

  const std::string& id() const { return id_; }
  const std::string& name() const { return name_; }

 private:
  static const char kKey[];

  std::string id_;
  std::string name_;
};

class DownloadsDownloadFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.download", DOWNLOADS_DOWNLOAD)
  DownloadsDownloadFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsDownloadFunction() override;

 private:
  void OnStarted(const base::FilePath& creator_suggested_filename,
                 extensions::api::downloads::FilenameConflictAction
                     creator_conflict_action,
                 download::DownloadItem* item,
                 download::DownloadInterruptReason interrupt_reason);
};

class DownloadsSearchFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.search", DOWNLOADS_SEARCH)
  DownloadsSearchFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsSearchFunction() override;
};

class DownloadsPauseFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.pause", DOWNLOADS_PAUSE)
  DownloadsPauseFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsPauseFunction() override;
};

class DownloadsResumeFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.resume", DOWNLOADS_RESUME)
  DownloadsResumeFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsResumeFunction() override;
};

class DownloadsCancelFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.cancel", DOWNLOADS_CANCEL)
  DownloadsCancelFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsCancelFunction() override;
};

class DownloadsEraseFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.erase", DOWNLOADS_ERASE)
  DownloadsEraseFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsEraseFunction() override;
};

class DownloadsRemoveFileFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.removeFile", DOWNLOADS_REMOVEFILE)
  DownloadsRemoveFileFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsRemoveFileFunction() override;

 private:
  void Done(bool success);
};

class DownloadsAcceptDangerFunction : public ExtensionFunction {
 public:
  using OnPromptCreatedCallback =
      base::OnceCallback<void(DownloadDangerPrompt*)>;
  static void OnPromptCreatedForTesting(
      OnPromptCreatedCallback* callback) {
    on_prompt_created_ = callback;
  }

  DECLARE_EXTENSION_FUNCTION("downloads.acceptDanger", DOWNLOADS_ACCEPTDANGER)
  DownloadsAcceptDangerFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsAcceptDangerFunction() override;
  void DangerPromptCallback(int download_id,
                            DownloadDangerPrompt::Action action);

 private:
  void PromptOrWait(int download_id, int retries);

  static OnPromptCreatedCallback* on_prompt_created_;
};

class DownloadsShowFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.show", DOWNLOADS_SHOW)
  DownloadsShowFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsShowFunction() override;
};

class DownloadsShowDefaultFolderFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION(
      "downloads.showDefaultFolder", DOWNLOADS_SHOWDEFAULTFOLDER)
  DownloadsShowDefaultFolderFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsShowDefaultFolderFunction() override;
};

class DownloadsOpenFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.open", DOWNLOADS_OPEN)
  DownloadsOpenFunction();

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

  ResponseAction Run() override;

  using OnPromptCreatedCallback = base::OnceCallback<void(DownloadOpenPrompt*)>;
  static void set_on_prompt_created_cb_for_testing(
      OnPromptCreatedCallback* on_prompt_created_cb) {
    on_prompt_created_cb_ = on_prompt_created_cb;
  }

 protected:
  ~DownloadsOpenFunction() override;

 private:
  void OpenPromptDone(int download_id, bool accept);

  static OnPromptCreatedCallback* on_prompt_created_cb_;
};

class DownloadsSetShelfEnabledFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.setShelfEnabled",
                             DOWNLOADS_SETSHELFENABLED)
  DownloadsSetShelfEnabledFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsSetShelfEnabledFunction() override;
};

class DownloadsSetUiOptionsFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.setUiOptions", DOWNLOADS_SETUIOPTIONS)
  DownloadsSetUiOptionsFunction();

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

  ResponseAction Run() override;

 protected:
  ~DownloadsSetUiOptionsFunction() override;
};

class DownloadsGetFileIconFunction : public ExtensionFunction {
 public:
  DECLARE_EXTENSION_FUNCTION("downloads.getFileIcon", DOWNLOADS_GETFILEICON)
  DownloadsGetFileIconFunction();

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

  ResponseAction Run() override;
  void SetIconExtractorForTesting(DownloadFileIconExtractor* extractor);

 protected:
  ~DownloadsGetFileIconFunction() override;

 private:
  void OnIconURLExtracted(const std::string& url);
  base::FilePath path_;
  std::unique_ptr<DownloadFileIconExtractor> icon_extractor_;
};

// Observes a single DownloadManager and many DownloadItems and dispatches
// onCreated and onErased events.
class ExtensionDownloadsEventRouter
    : public extensions::EventRouter::Observer,
      public extensions::ExtensionRegistryObserver,
      public download::AllDownloadItemNotifier::Observer {
 public:
  typedef base::OnceCallback<void(
      const base::FilePath& changed_filename,
      download::DownloadPathReservationTracker::FilenameConflictAction)>
      FilenameChangedCallback;

  static void SetDetermineFilenameTimeoutSecondsForTesting(int s);

  // The logic for how to handle conflicting filename suggestions from multiple
  // extensions is split out here for testing.
  static void DetermineFilenameInternal(
      const base::FilePath& filename,
      extensions::api::downloads::FilenameConflictAction conflict_action,
      const std::string& suggesting_extension_id,
      const base::Time& suggesting_install_time,
      const std::string& incumbent_extension_id,
      const base::Time& incumbent_install_time,
      std::string* winner_extension_id,
      base::FilePath* determined_filename,
      extensions::api::downloads::FilenameConflictAction*
        determined_conflict_action,
      extensions::WarningSet* warnings);

  // A downloads.onDeterminingFilename listener has returned. If the extension
  // wishes to override the download's filename, then |filename| will be
  // non-empty. |filename| will be interpreted as a relative path, appended to
  // the default downloads directory. If the extension wishes to overwrite any
  // existing files, then |overwrite| will be true. Returns true on success,
  // false otherwise.
  static bool DetermineFilename(
      content::BrowserContext* browser_context,
      bool include_incognito,
      const std::string& ext_id,
      int download_id,
      const base::FilePath& filename,
      extensions::api::downloads::FilenameConflictAction conflict_action,
      std::string* error);

  explicit ExtensionDownloadsEventRouter(
      Profile* profile, content::DownloadManager* manager);

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

  ~ExtensionDownloadsEventRouter() override;

  void SetUiEnabled(const extensions::Extension* extension, bool enabled);
  bool IsUiEnabled() const;

  // Called by ChromeDownloadManagerDelegate during the filename determination
  // process, allows extensions to change the item's target filename. If no
  // extension wants to change the target filename, then |filename_changed| will
  // be called with an empty filename and the filename determination process
  // will continue as normal. If an extension wants to change the target
  // filename, then |filename_changed| will be called with the new filename and
  // a flag indicating whether the new file should overwrite any old files of
  // the same name.
  void OnDeterminingFilename(download::DownloadItem* item,
                             const base::FilePath& suggested_path,
                             FilenameChangedCallback filename_changed);

  // AllDownloadItemNotifier::Observer.
  void OnDownloadCreated(content::DownloadManager* manager,
                         download::DownloadItem* download_item) override;
  void OnDownloadUpdated(content::DownloadManager* manager,
                         download::DownloadItem* download_item) override;
  void OnDownloadRemoved(content::DownloadManager* manager,
                         download::DownloadItem* download_item) override;

  // extensions::EventRouter::Observer.
  void OnListenerRemoved(const extensions::EventListenerInfo& details) override;

  void CheckForHistoryFilesRemoval();

 private:
  void DispatchEvent(events::HistogramValue histogram_value,
                     const std::string& event_name,
                     bool include_incognito,
                     Event::WillDispatchCallback will_dispatch_callback,
                     base::Value json_arg);

  // extensions::ExtensionRegistryObserver.
  void OnExtensionUnloaded(content::BrowserContext* browser_context,
                           const extensions::Extension* extension,
                           extensions::UnloadedExtensionReason reason) override;

  raw_ptr<Profile> profile_;
  download::AllDownloadItemNotifier notifier_;
  std::set<const extensions::Extension*> ui_disabling_extensions_;

  base::Time last_checked_removal_;

  // Listen to extension unloaded notifications.
  base::ScopedObservation<extensions::ExtensionRegistry,
                          extensions::ExtensionRegistryObserver>
      extension_registry_observation_{this};
};

}  // namespace extensions

#endif  // CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_

四、最后读者可以加载examples/api/downloads

       扩展在chrome\browser\extensions\api\downloads\downloads_api.cc 打断点看下调用堆栈 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值