Convert utility process extension Unpacker IPC to mojo
Add ExtensionUnpacker mojo, used to (unzip and) unpack a chrome
extension, and expose it to the browser via the utility process
policy file. Make callers use a utility process mojo client.
Add [Native] IPC enum param traits via a mojo typemap to handle
extensions::Manifest::Location. Set the wire limit for the enum
value to one less than Manifest::NUM_LOCATIONS (for compat with
the pre-existing custom traits removed in this patch since this
patch auto-generates them: manifest_location_param_traits.cc).
In the extensions/utility/utility_handler.cc, retain the CHECKs
on the Manifest::Location enum limits while bug 692069 is still
being investigated.
Move DecodeImages declarations from the extension messages-file
into its own file (extension_utility_types.h) to decouple those
declarations from this messages-file. A follow-up patch deletes
the messages-file so DecodeImages needs a new home.
Update all BUILD.gn for using clients to directly depend on the
//extensions/common:common target (and hence, its :mojo) to fix
post-compile step failures (warning about under-specified BUILD
files via "targets is_dirty" errors, see review comment #169).
Add TestContentBrowserClient to the extension test harness, and
also an overlay file in test/data (needed to expose the mojo in
the extension test harness to the unit tests listed below).
Covered by existing unit tests:
{sandboxed_unpacker, zipfile_installer}_unittest.cc
BUG=691410
Review-Url: https://codereview.chromium.org/2697463002
Cr-Commit-Position: refs/heads/master@{#457374}
diff --git a/extensions/utility/unpacker.cc b/extensions/utility/unpacker.cc
index bab2f98..e946013 100644
--- a/extensions/utility/unpacker.cc
+++ b/extensions/utility/unpacker.cc
@@ -25,7 +25,7 @@
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_l10n_util.h"
-#include "extensions/common/extension_utility_messages.h"
+#include "extensions/common/extension_utility_types.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/file_util.h"
#include "extensions/common/manifest.h"
diff --git a/extensions/utility/unpacker.h b/extensions/utility/unpacker.h
index fa77b69f..63b20be 100644
--- a/extensions/utility/unpacker.h
+++ b/extensions/utility/unpacker.h
@@ -53,6 +53,10 @@
base::DictionaryValue* parsed_manifest() { return parsed_manifest_.get(); }
base::DictionaryValue* parsed_catalogs() { return parsed_catalogs_.get(); }
+ std::unique_ptr<base::DictionaryValue> TakeParsedManifest() {
+ return std::move(parsed_manifest_);
+ }
+
private:
// Write the decoded images to kDecodedImagesFilename. We do this instead
// of sending them over IPC, since they are so large. Returns true on
diff --git a/extensions/utility/utility_handler.cc b/extensions/utility/utility_handler.cc
index 59fcdfe..96a4445 100644
--- a/extensions/utility/utility_handler.cc
+++ b/extensions/utility/utility_handler.cc
@@ -6,12 +6,10 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/i18n/rtl.h"
#include "content/public/utility/utility_thread.h"
#include "extensions/common/constants.h"
-#include "extensions/common/extension.h"
#include "extensions/common/extension_l10n_util.h"
+#include "extensions/common/extension_unpacker.mojom.h"
#include "extensions/common/extension_utility_messages.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/manifest.h"
@@ -20,6 +18,8 @@
#include "extensions/utility/unpacker.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/service_manager/public/cpp/interface_registry.h"
#include "third_party/zlib/google/zip.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_switches.h"
@@ -28,24 +28,84 @@
namespace {
-bool Send(IPC::Message* message) {
- return content::UtilityThread::Get()->Send(message);
-}
+class ExtensionUnpackerImpl : public extensions::mojom::ExtensionUnpacker {
+ public:
+ ExtensionUnpackerImpl() = default;
+ ~ExtensionUnpackerImpl() override = default;
-void ReleaseProcessIfNeeded() {
- content::UtilityThread::Get()->ReleaseProcessIfNeeded();
-}
+ static void Create(extensions::mojom::ExtensionUnpackerRequest request) {
+ mojo::MakeStrongBinding(base::MakeUnique<ExtensionUnpackerImpl>(),
+ std::move(request));
+ }
-const char kExtensionHandlerUnzipError[] =
- "Could not unzip extension for install.";
+ private:
+ // extensions::mojom::ExtensionUnpacker:
+ void Unzip(const base::FilePath& file,
+ const base::FilePath& path,
+ const UnzipCallback& callback) override {
+ std::unique_ptr<base::DictionaryValue> manifest;
+ if (UnzipFileManifestIntoPath(file, path, &manifest)) {
+ callback.Run(UnzipFileIntoPath(file, path, std::move(manifest)));
+ } else {
+ callback.Run(false);
+ }
+ }
+
+ void Unpack(const base::FilePath& path,
+ const std::string& extension_id,
+ Manifest::Location location,
+ int32_t creation_flags,
+ const UnpackCallback& callback) override {
+ CHECK_GT(location, Manifest::INVALID_LOCATION);
+ CHECK_LT(location, Manifest::NUM_LOCATIONS);
+ DCHECK(ExtensionsClient::Get());
+
+ content::UtilityThread::Get()->EnsureBlinkInitialized();
+
+ Unpacker unpacker(path.DirName(), path, extension_id, location,
+ creation_flags);
+ if (unpacker.Run()) {
+ callback.Run(base::string16(), unpacker.TakeParsedManifest());
+ } else {
+ callback.Run(unpacker.error_message(), nullptr);
+ }
+ }
+
+ static bool UnzipFileManifestIntoPath(
+ const base::FilePath& file,
+ const base::FilePath& path,
+ std::unique_ptr<base::DictionaryValue>* manifest) {
+ if (zip::UnzipWithFilterCallback(
+ file, path, base::Bind(&Unpacker::IsManifestFile), false)) {
+ std::string error;
+ *manifest = Unpacker::ReadManifest(path, &error);
+ return error.empty() && manifest->get();
+ }
+
+ return false;
+ }
+
+ static bool UnzipFileIntoPath(
+ const base::FilePath& file,
+ const base::FilePath& path,
+ std::unique_ptr<base::DictionaryValue> manifest) {
+ Manifest internal(Manifest::INTERNAL, std::move(manifest));
+ // TODO(crbug.com/645263): This silently ignores blocked file types.
+ // Add install warnings.
+ return zip::UnzipWithFilterCallback(
+ file, path,
+ base::Bind(&Unpacker::ShouldExtractFile, internal.is_theme()),
+ true /* log_skipped_files */);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionUnpackerImpl);
+};
} // namespace
-UtilityHandler::UtilityHandler() {
-}
+UtilityHandler::UtilityHandler() = default;
-UtilityHandler::~UtilityHandler() {
-}
+UtilityHandler::~UtilityHandler() = default;
// static
void UtilityHandler::UtilityThreadStarted() {
@@ -55,13 +115,23 @@
extension_l10n_util::SetProcessLocale(lang);
}
+// static
+void UtilityHandler::ExposeInterfacesToBrowser(
+ service_manager::InterfaceRegistry* registry,
+ bool running_elevated) {
+ // If our process runs with elevated privileges, only add elevated Mojo
+ // services to the interface registry.
+ if (running_elevated)
+ return;
+
+ registry->AddInterface(base::Bind(&ExtensionUnpackerImpl::Create));
+}
+
bool UtilityHandler::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(UtilityHandler, message)
IPC_MESSAGE_HANDLER(ExtensionUtilityMsg_ParseUpdateManifest,
OnParseUpdateManifest)
- IPC_MESSAGE_HANDLER(ExtensionUtilityMsg_UnzipToDir, OnUnzipToDir)
- IPC_MESSAGE_HANDLER(ExtensionUtilityMsg_UnpackExtension, OnUnpackExtension)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -70,73 +140,15 @@
void UtilityHandler::OnParseUpdateManifest(const std::string& xml) {
UpdateManifest manifest;
if (!manifest.Parse(xml)) {
- Send(new ExtensionUtilityHostMsg_ParseUpdateManifest_Failed(
- manifest.errors()));
+ content::UtilityThread::Get()->Send(
+ new ExtensionUtilityHostMsg_ParseUpdateManifest_Failed(
+ manifest.errors()));
} else {
- Send(new ExtensionUtilityHostMsg_ParseUpdateManifest_Succeeded(
- manifest.results()));
+ content::UtilityThread::Get()->Send(
+ new ExtensionUtilityHostMsg_ParseUpdateManifest_Succeeded(
+ manifest.results()));
}
- ReleaseProcessIfNeeded();
+ content::UtilityThread::Get()->ReleaseProcessIfNeeded();
}
-void UtilityHandler::OnUnzipToDir(const base::FilePath& zip_path,
- const base::FilePath& dir) {
- // First extract only the manifest to determine the extension type.
- if (!zip::UnzipWithFilterCallback(zip_path, dir,
- base::Bind(&Unpacker::IsManifestFile),
- false /* log_skipped_files */)) {
- Send(new ExtensionUtilityHostMsg_UnzipToDir_Failed(
- std::string(kExtensionHandlerUnzipError)));
- ReleaseProcessIfNeeded();
- return;
- }
-
- // Load the manifest.
- std::string error;
- std::unique_ptr<base::DictionaryValue> dict =
- Unpacker::ReadManifest(dir, &error);
- if (!dict.get()) {
- Send(new ExtensionUtilityHostMsg_UnzipToDir_Failed(
- std::string(kExtensionHandlerUnzipError)));
- ReleaseProcessIfNeeded();
- return;
- }
-
- Manifest manifest(Manifest::INTERNAL, std::move(dict));
- base::Callback<bool(const base::FilePath&)> filetype_filter_cb =
- base::Bind(&Unpacker::ShouldExtractFile, manifest.is_theme());
-
- // TODO(crbug.com/645263): This silently ignores blocked file types.
- // Add install warnings.
- if (!zip::UnzipWithFilterCallback(zip_path, dir, filetype_filter_cb,
- true /* log_skipped_files */)) {
- Send(new ExtensionUtilityHostMsg_UnzipToDir_Failed(
- std::string(kExtensionHandlerUnzipError)));
- } else {
- Send(new ExtensionUtilityHostMsg_UnzipToDir_Succeeded(dir));
- }
- ReleaseProcessIfNeeded();
-}
-
-void UtilityHandler::OnUnpackExtension(const base::FilePath& directory_path,
- const std::string& extension_id,
- int location,
- int creation_flags) {
- CHECK_GT(location, Manifest::INVALID_LOCATION);
- CHECK_LT(location, Manifest::NUM_LOCATIONS);
- DCHECK(ExtensionsClient::Get());
- content::UtilityThread::Get()->EnsureBlinkInitialized();
- Unpacker unpacker(directory_path.DirName(), directory_path, extension_id,
- static_cast<Manifest::Location>(location), creation_flags);
- if (unpacker.Run()) {
- Send(new ExtensionUtilityHostMsg_UnpackExtension_Succeeded(
- *unpacker.parsed_manifest()));
- } else {
- Send(new ExtensionUtilityHostMsg_UnpackExtension_Failed(
- unpacker.error_message()));
- }
- ReleaseProcessIfNeeded();
-}
-
-
} // namespace extensions
diff --git a/extensions/utility/utility_handler.h b/extensions/utility/utility_handler.h
index 2bc12f4..2378dcd 100644
--- a/extensions/utility/utility_handler.h
+++ b/extensions/utility/utility_handler.h
@@ -7,17 +7,16 @@
#include <string>
-#include "base/callback.h"
#include "base/macros.h"
-namespace base {
-class FilePath;
-}
-
namespace IPC {
class Message;
}
+namespace service_manager {
+class InterfaceRegistry;
+}
+
namespace extensions {
// A handler for extensions-related IPC from within utility processes.
@@ -28,16 +27,15 @@
static void UtilityThreadStarted();
+ static void ExposeInterfacesToBrowser(
+ service_manager::InterfaceRegistry* registry,
+ bool running_elevated);
+
bool OnMessageReceived(const IPC::Message& message);
private:
// IPC message handlers.
void OnParseUpdateManifest(const std::string& xml);
- void OnUnzipToDir(const base::FilePath& zip_path, const base::FilePath& dir);
- void OnUnpackExtension(const base::FilePath& directory_path,
- const std::string& extension_id,
- int location,
- int creation_flags);
DISALLOW_COPY_AND_ASSIGN(UtilityHandler);
};