initial revision for imageloader
- also add unit tests (run them by FEATURES="test" emerge-${BOARD} ...)
BUG=chromium:616816
TEST=emerge-cyan chromeos-base/imageloader && cros deploy <ip for cyan> chromeos-base/imageloader
Change-Id: Idb3593ac65a83dedb85d78c42104d1b4ead5c7e0
Reviewed-on: https://chromium-review.googlesource.com/348080
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Andrew de los Reyes <adlr@chromium.org>
Commit-Queue: Ashish Gaurav <ashishgaurav@chromium.org>
Tested-by: Ashish Gaurav <ashishgaurav@chromium.org>
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8f2fe3a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# src/platform/imageloader
+
+This aims to provide a generic utility to load (mount) and unload (unmount)
+verified disk images through DBus IPC.
+
+# Binaries
+
+* `imageloader`
+* `imageloadclient`
+
+`imageloader` can be run as root and can handle mounting and unmounting of
+disk images. `imageloadclient` is a simple client (intended to be run as
+chronos) that can talk to `imageloader` and ask it to mount and unmount stuff.
+When `imageloader` is not running, DBus can invoke it via the one time
+run option (`imageloader -o`) and get the task done.
diff --git a/imageloadclient-glue.xml b/imageloadclient-glue.xml
new file mode 100644
index 0000000..f78ae28
--- /dev/null
+++ b/imageloadclient-glue.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<!--
+ Copyright 2016 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<node name="/org/chromium/ImageLoader">
+ <interface name="org.chromium.ImageLoaderInterface">
+ <method name="RegisterComponent">
+ <arg type="s" name="name" direction="in"/>
+ <arg type="s" name="version" direction="in" />
+ <arg type="s" name="fs_image_abs_path" direction="in"/>
+ <arg type="b" name="success" direction="out" />
+ </method>
+ <method name="GetComponentVersion">
+ <arg type="s" name="name" direction="in" />
+ <arg type="s" name="version" direction="out" />
+ </method>
+ <method name="LoadComponent">
+ <arg type="s" name="name" direction="in" />
+ <arg type="s" name="mount_point" direction="out" />
+ </method>
+ <method name="UnloadComponent">
+ <arg type="s" name="name" direction="in" />
+ <arg type="b" name="success" direction="out" />
+ </method>
+ </interface>
+</node>
diff --git a/imageloadclient.cc b/imageloadclient.cc
new file mode 100644
index 0000000..42620c1
--- /dev/null
+++ b/imageloadclient.cc
@@ -0,0 +1,124 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "imageloadclient.h"
+
+#include <signal.h>
+
+#include <iostream>
+#include <string>
+
+#include <base/command_line.h>
+#include <base/files/file_path.h>
+#include <base/logging.h>
+#include <pthread.h>
+
+#include "imageloader_common.h"
+
+namespace imageloader {
+
+ImageLoadClient::ImageLoadClient(DBus::Connection* conn, const char* path,
+ const char* name)
+ : DBus::ObjectProxy(*conn, path, name) {}
+
+void ImageLoadClient::RegisterComponentCallback(const bool& success,
+ const ::DBus::Error& err,
+ void*) {
+ if (success) {
+ LOG(INFO) << "Success.";
+ } else {
+ LOG(INFO) << "Failure.";
+ }
+}
+
+void ImageLoadClient::GetComponentVersionCallback(const std::string& version,
+ const ::DBus::Error& err,
+ void*) {
+ if (version == kBadResult) {
+ LOG(INFO) << "Failure.";
+ } else {
+ LOG(INFO) << "Version = " << version;
+ }
+}
+
+void ImageLoadClient::LoadComponentCallback(const std::string& mount_point,
+ const ::DBus::Error& err, void*) {
+ if (mount_point == kBadResult) {
+ LOG(INFO) << "Could not mount.";
+ } else {
+ LOG(INFO) << "Mounted at " << mount_point << ".";
+ }
+}
+
+void ImageLoadClient::UnloadComponentCallback(const bool& success,
+ const ::DBus::Error& err,
+ void*) {
+ if (success) {
+ LOG(INFO) << "Success.";
+ } else {
+ LOG(INFO) << "Failure.";
+ }
+}
+
+namespace {
+
+void *TestCalls(void *arg) {
+ ImageLoadClient *client = reinterpret_cast<ImageLoadClient *>(arg);
+ while (1) {
+ std::string inp, name, abs_path, rel_path, version;
+ std::cin >> inp;
+ if (inp == "rc") { // RegisterComponent
+ std::cin >> name;
+ std::cin >> version;
+ std::cin >> rel_path;
+ char* c_abs_path = realpath(rel_path.c_str(), NULL);
+ if (c_abs_path != NULL) {
+ abs_path = std::string(c_abs_path);
+ client->RegisterComponentAsync(name, version, abs_path, NULL);
+ free(c_abs_path);
+ } else {
+ PLOG(ERROR) << "realpath : " << rel_path;
+ }
+ } else if (inp == "gcv") { // GetComponentVersion
+ std::cin >> name;
+ client->GetComponentVersionAsync(name, NULL);
+ } else if (inp == "lc") { // LoadComponent
+ std::cin >> name;
+ client->LoadComponentAsync(name, NULL);
+ } else if (inp == "uc") { // UnloadComponent
+ std::cin >> name;
+ client->UnloadComponentAsync(name, NULL);
+ }
+ }
+ return NULL;
+}
+
+} // namespace {}
+
+} // namespace imageloader
+
+int main(int argc, char** argv) {
+ signal(SIGTERM, imageloader::OnQuit);
+ signal(SIGINT, imageloader::OnQuit);
+
+ base::CommandLine::Init(argc, argv);
+ logging::LoggingSettings settings;
+ logging::InitLogging(settings);
+
+ DBus::_init_threading();
+ DBus::BusDispatcher dispatcher;
+ DBus::default_dispatcher = &dispatcher;
+ DBus::Connection conn = DBus::Connection::SystemBus();
+
+ imageloader::ImageLoadClient client(&conn, imageloader::kImageLoaderPath,
+ imageloader::kImageLoaderName);
+
+ pthread_t thread;
+ pthread_create(&thread, NULL, imageloader::TestCalls, &client);
+
+ dispatcher.enter();
+ LOG(INFO) << "Exiting ...";
+
+ return 0;
+}
diff --git a/imageloadclient.h b/imageloadclient.h
new file mode 100644
index 0000000..c948aef
--- /dev/null
+++ b/imageloadclient.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IMAGELOADER_IMAGELOADCLIENT_H_
+#define IMAGELOADER_IMAGELOADCLIENT_H_
+
+#include <string>
+
+#include <dbus-c++/dbus.h>
+
+#include "imageloadclient-glue.h"
+
+namespace imageloader {
+
+// This is a simple client to use imageloader's service in non-root mode.
+class ImageLoadClient
+ : public org::chromium::ImageLoaderInterface_proxy,
+ public DBus::ObjectProxy {
+ public:
+ // Initialize the ImageLoadClient instance.
+ ImageLoadClient(DBus::Connection* conn, const char* path, const char* name);
+
+ void RegisterComponentCallback(const bool& success, const ::DBus::Error& err,
+ void* data);
+
+ void GetComponentVersionCallback(const std::string& version,
+ const ::DBus::Error& err, void* data);
+
+ void LoadComponentCallback(const std::string& mount_point,
+ const ::DBus::Error& err, void* data);
+
+ void UnloadComponentCallback(const bool& success, const ::DBus::Error& err,
+ void* data);
+};
+
+} // namespace imageloader
+
+#endif // IMAGELOADER_IMAGELOADCLIENT_H_
diff --git a/imageloader-glue.xml b/imageloader-glue.xml
new file mode 100644
index 0000000..f78ae28
--- /dev/null
+++ b/imageloader-glue.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<!--
+ Copyright 2016 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<node name="/org/chromium/ImageLoader">
+ <interface name="org.chromium.ImageLoaderInterface">
+ <method name="RegisterComponent">
+ <arg type="s" name="name" direction="in"/>
+ <arg type="s" name="version" direction="in" />
+ <arg type="s" name="fs_image_abs_path" direction="in"/>
+ <arg type="b" name="success" direction="out" />
+ </method>
+ <method name="GetComponentVersion">
+ <arg type="s" name="name" direction="in" />
+ <arg type="s" name="version" direction="out" />
+ </method>
+ <method name="LoadComponent">
+ <arg type="s" name="name" direction="in" />
+ <arg type="s" name="mount_point" direction="out" />
+ </method>
+ <method name="UnloadComponent">
+ <arg type="s" name="name" direction="in" />
+ <arg type="b" name="success" direction="out" />
+ </method>
+ </interface>
+</node>
diff --git a/imageloader.cc b/imageloader.cc
new file mode 100644
index 0000000..c9a9916
--- /dev/null
+++ b/imageloader.cc
@@ -0,0 +1,216 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "imageloader.h"
+
+#include <fcntl.h>
+#include <linux/loop.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+
+#include <sstream>
+#include <string>
+#include <utility>
+
+#include <base/command_line.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_file.h>
+#include <base/guid.h>
+#include <base/logging.h>
+#include <brillo/flag_helper.h>
+#include <dbus-c++/error.h>
+
+#include "imageloader_common.h"
+
+namespace imageloader {
+
+using base::CreateDirectory;
+using base::DeleteFile;
+using base::FilePath;
+using base::GenerateGUID;
+using base::PathExists;
+using base::ScopedFD;
+
+namespace {
+
+using imageloader::kBadResult;
+
+// Generate a good enough (unique) mount point.
+FilePath GenerateMountPoint(const char prefix[]) {
+ return FilePath(prefix + GenerateGUID());
+}
+
+} // namespace {}
+
+// Mount component at location generated.
+std::string ImageLoader::LoadComponentUtil(const std::string& name) {
+ FilePath mount_point = GenerateMountPoint("/mnt/");
+ // Is this somehow taken up by any other name or mount?
+ for (auto it = mounts.begin(); it != mounts.end(); ++it) {
+ if ((it->second).first == mount_point) {
+ return kBadResult;
+ }
+ }
+ if (PathExists(mount_point)) {
+ LOG(INFO) << "Generated mount_point is already stat-able : "
+ << mount_point.value();
+ return kBadResult;
+ }
+ // The mount point is not yet taken, so go ahead.
+ ScopedFD loopctl_fd(open("/dev/loop-control", O_RDONLY | O_CLOEXEC));
+ if (!loopctl_fd.is_valid()) {
+ PLOG(ERROR) << "loopctl_fd";
+ return kBadResult;
+ }
+ int device_free_number = ioctl(loopctl_fd.get(), LOOP_CTL_GET_FREE);
+ if (device_free_number < 0) {
+ PLOG(ERROR) << "ioctl : LOOP_CTL_GET_FREE";
+ return kBadResult;
+ }
+ std::ostringstream device_path;
+ device_path << "/dev/loop" << device_free_number;
+ ScopedFD device_path_fd(open(device_path.str().c_str(),
+ O_RDONLY | O_CLOEXEC));
+ if (!device_path_fd.is_valid()) {
+ PLOG(ERROR) << "device_path_fd";
+ return kBadResult;
+ }
+ ScopedFD fs_image_fd(open(reg[name].second.value().c_str(),
+ O_RDONLY | O_CLOEXEC));
+ if (!fs_image_fd.is_valid()) {
+ PLOG(ERROR) << "fs_image_fd";
+ return kBadResult;
+ }
+ if (ioctl(device_path_fd.get(), LOOP_SET_FD, fs_image_fd.get()) < 0) {
+ PLOG(ERROR) << "ioctl: LOOP_SET_FD";
+ return kBadResult;
+ }
+ if (!CreateDirectory(mount_point)) {
+ PLOG(ERROR) << "CreateDirectory : " << mount_point.value();
+ ioctl(device_path_fd.get(), LOOP_CLR_FD, 0);
+ return kBadResult;
+ }
+ if (mount(device_path.str().c_str(), mount_point.value().c_str(), "squashfs",
+ MS_RDONLY | MS_NOSUID | MS_NODEV, "") < 0) {
+ PLOG(ERROR) << "mount";
+ ioctl(device_path_fd.get(), LOOP_CLR_FD, 0);
+ return kBadResult;
+ }
+ mounts[name] = std::make_pair(mount_point, FilePath(device_path.str()));
+ return mount_point.value();
+}
+
+// Unmount the given component.
+bool ImageLoader::UnloadComponentUtil(const std::string& name) {
+ std::string device_path = mounts[name].second.value();
+ if (umount(mounts[name].first.value().c_str()) < 0) {
+ PLOG(ERROR) << "umount";
+ return false;
+ }
+ const FilePath fp_mount_point(mounts[name].first);
+ if (!DeleteFile(fp_mount_point, false)) {
+ PLOG(ERROR) << "DeleteFile : " << fp_mount_point.value();
+ return false;
+ }
+ ScopedFD device_path_fd(open(device_path.c_str(), O_RDONLY | O_CLOEXEC));
+ if (!device_path_fd.is_valid()) {
+ PLOG(ERROR) << "device_path_fd";
+ return false;
+ }
+ if (ioctl(device_path_fd.get(), LOOP_CLR_FD, 0) < 0) {
+ PLOG(ERROR) << "ioctl: LOOP_CLR_FD";
+ return false;
+ }
+ mounts.erase(mounts.find(name));
+ return true;
+}
+
+// Following functions are required directly for the DBus functionality.
+
+ImageLoader::ImageLoader(DBus::Connection* conn)
+ : DBus::ObjectAdaptor(*conn, kImageLoaderPath) {}
+
+bool ImageLoader::RegisterComponent(const std::string& name,
+ const std::string& version,
+ const std::string& fs_image_abs_path,
+ ::DBus::Error& err) {
+ if (reg.find(name) == reg.end()) {
+ reg[name] = std::make_pair(version, FilePath(fs_image_abs_path));
+ LOG(INFO) << "Registered (" << name << ", " << version << ", "
+ << fs_image_abs_path << ")";
+ return true;
+ }
+ LOG(ERROR) <<
+ "Couldn't register, entry with specified name already exists : "
+ << name;
+ return false;
+}
+
+std::string ImageLoader::GetComponentVersion(const std::string& name,
+ ::DBus::Error& err) {
+ if (reg.find(name) != reg.end()) {
+ LOG(INFO) << "Found entry (" << name << ", " << reg[name].first << ", "
+ << reg[name].second.value() << ")";
+ return reg[name].first;
+ }
+ LOG(ERROR) << "Entry not found : " << name;
+ return kBadResult;
+}
+
+std::string ImageLoader::LoadComponent(const std::string& name,
+ ::DBus::Error& err) {
+ if (reg.find(name) != reg.end()) {
+ if (mounts.find(name) != mounts.end()) {
+ LOG(ERROR) << "Already mounted at " << mounts[name].first.value() << ".";
+ return kBadResult;
+ }
+ std::string mount_point = LoadComponentUtil(name);
+ if (mount_point == kBadResult) {
+ LOG(ERROR) << "Unable to mount : " << mount_point;
+ return kBadResult;
+ }
+ LOG(INFO) << "Mounted successfully at " << mount_point << ".";
+ return mount_point;
+ }
+ LOG(ERROR) << "Entry not found : " << name;
+ return kBadResult;
+}
+
+bool ImageLoader::UnloadComponent(const std::string& name,
+ ::DBus::Error& err) {
+ if (UnloadComponentUtil(name)) {
+ LOG(INFO) << "Unmount " << name << " successful.";
+ return true;
+ }
+ LOG(ERROR) << "Unmount " << name << " unsucessful.";
+ return false;
+}
+
+} // namespace imageloader
+
+int main(int argc, char **argv) {
+ signal(SIGTERM, imageloader::OnQuit);
+ signal(SIGINT, imageloader::OnQuit);
+
+ DEFINE_bool(o, false, "run once");
+ brillo::FlagHelper::Init(argc, argv, "imageloader");
+
+ logging::LoggingSettings settings;
+ logging::InitLogging(settings);
+
+ DBus::BusDispatcher dispatcher;
+ DBus::default_dispatcher = &dispatcher;
+ DBus::Connection conn = DBus::Connection::SystemBus();
+ conn.request_name(imageloader::kImageLoaderName);
+ imageloader::ImageLoader helper(&conn);
+
+ if (FLAGS_o) {
+ dispatcher.dispatch_pending();
+ } else {
+ dispatcher.enter();
+ }
+ return 0;
+}
diff --git a/imageloader.gyp b/imageloader.gyp
new file mode 100644
index 0000000..f69f018
--- /dev/null
+++ b/imageloader.gyp
@@ -0,0 +1,100 @@
+# Copyright 2016 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'variables': {
+ 'deps': [
+ 'libchrome-<(libbase_ver)',
+ 'dbus-c++-1',
+ ],
+ # imageloader uses try/catch to interact with dbus-c++
+ 'enable_exceptions': 1,
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'libimageloader_common',
+ 'type': 'static_library',
+ 'sources': [
+ 'imageloader_common.cc',
+ 'imageloader_common.h',
+ ],
+ },
+ {
+ 'target_name': 'imageloader-glue',
+ 'type': 'none',
+ 'variables': {
+ 'xml2cpp_type': 'adaptor',
+ 'xml2cpp_in_dir': '.',
+ 'xml2cpp_out_dir': 'include',
+ },
+ 'sources': [
+ '<(xml2cpp_in_dir)/imageloader-glue.xml',
+ ],
+ 'includes': ['../../platform2/common-mk/xml2cpp.gypi'],
+ },
+ {
+ 'target_name': 'imageloadclient-glue',
+ 'type': 'none',
+ 'variables': {
+ 'xml2cpp_type': 'proxy',
+ 'xml2cpp_in_dir': '.',
+ 'xml2cpp_out_dir': 'include',
+ },
+ 'sources': [
+ '<(xml2cpp_in_dir)/imageloadclient-glue.xml',
+ ],
+ 'includes': ['../../platform2/common-mk/xml2cpp.gypi'],
+ },
+ {
+ 'target_name': 'imageloader',
+ 'type': 'executable',
+ 'variables': {
+ 'deps': ['libbrillo-<(libbase_ver)'],
+ },
+ 'dependencies': [
+ 'imageloader-glue',
+ 'libimageloader_common',
+ ],
+ 'sources': [
+ 'imageloader.cc',
+ 'imageloader.h',
+ 'imageloader-glue.h',
+ ],
+ },
+ {
+ 'target_name': 'imageloadclient',
+ 'type': 'executable',
+ 'dependencies': [
+ 'imageloadclient-glue',
+ 'libimageloader_common',
+ ],
+ 'sources': [
+ 'imageloadclient.cc',
+ 'imageloadclient.h',
+ 'imageloadclient-glue.h',
+ ],
+ 'libraries': ['-lpthread'],
+ },
+ ],
+ 'conditions': [
+ ['USE_test == 1', {
+ 'targets': [
+ {
+ 'target_name': 'run_tests',
+ 'type': 'executable',
+ 'includes': ['../../platform2/common-mk/common_test.gypi'],
+ 'dependencies': [
+ 'libimageloader_common',
+ ],
+ 'sources': [
+ 'run_tests.cc',
+ 'imageloader_common_unittest.cc'
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/imageloader.h b/imageloader.h
new file mode 100644
index 0000000..49a7abc
--- /dev/null
+++ b/imageloader.h
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef IMAGELOADER_IMAGELOADER_H_
+#define IMAGELOADER_IMAGELOADER_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include <base/files/file_path.h>
+#include <dbus-c++/dbus.h>
+
+#include "imageloader-glue.h"
+
+namespace imageloader {
+
+// This is a utility that handles mounting and unmounting of
+// verified filesystem images that might include binaries intended
+// to be run as read only.
+class ImageLoader
+ : org::chromium::ImageLoaderInterface_adaptor,
+ public DBus::ObjectAdaptor {
+ public:
+ // Instantiate a D-Bus Helper Instance
+ explicit ImageLoader(DBus::Connection* conn);
+
+ // Register a component.
+ bool RegisterComponent(const std::string& name, const std::string& version,
+ const std::string& fs_image_abs_path,
+ ::DBus::Error& err);
+
+ // Get component version given component name.
+ std::string GetComponentVersion(const std::string& name, ::DBus::Error& err);
+
+ // Load the specified component.
+ std::string LoadComponent(const std::string& name, ::DBus::Error& err);
+ std::string LoadComponentUtil(const std::string& name);
+
+ // Unload the specified component.
+ bool UnloadComponent(const std::string& name, ::DBus::Error& err);
+ bool UnloadComponentUtil(const std::string& name);
+ private:
+ // "mounts" keeps track of what has been mounted.
+ // mounts = (name, (mount_point, device_path))
+ std::map<std::string, std::pair<base::FilePath, base::FilePath>> mounts;
+ // "reg" keeps track of registered components.
+ // reg = (name, (version, fs_image_abs_path))
+ std::map<std::string, std::pair<std::string, base::FilePath>> reg;
+};
+
+} // namespace imageloader
+
+#endif // IMAGELOADER_IMAGELOADER_H_
diff --git a/imageloader_common.cc b/imageloader_common.cc
new file mode 100644
index 0000000..af96772
--- /dev/null
+++ b/imageloader_common.cc
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "imageloader_common.h"
+
+#include <dbus-c++/dbus.h>
+
+namespace imageloader {
+
+void OnQuit(int sig) {
+ if (DBus::default_dispatcher)
+ DBus::default_dispatcher->leave();
+}
+
+} // namespace imageloader
diff --git a/imageloader_common.h b/imageloader_common.h
new file mode 100644
index 0000000..bd51e58
--- /dev/null
+++ b/imageloader_common.h
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IMAGELOADER_IMAGELOADER_COMMON_H_
+#define IMAGELOADER_IMAGELOADER_COMMON_H_
+
+namespace imageloader {
+
+const char kBadResult[] = "";
+const char kImageLoaderName[] = "org.chromium.ImageLoader";
+const char kImageLoaderPath[] = "/org/chromium/ImageLoader";
+
+void OnQuit(int sig);
+
+} // namespace imageloader
+
+#endif // IMAGELOADER_IMAGELOADER_COMMON_H_
diff --git a/org.chromium.ImageLoader.conf b/org.chromium.ImageLoader.conf
new file mode 100644
index 0000000..2d1f65d
--- /dev/null
+++ b/org.chromium.ImageLoader.conf
@@ -0,0 +1,33 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<!--
+ Copyright 2016 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+
+ This file will be installed at /etc/dbus-1/system.d on Chromium OS.
+-->
+<busconfig>
+ <policy user="root">
+ <allow own="org.chromium.ImageLoader" />
+ <allow receive_sender="org.chromium.ImageLoader" />
+ <allow send_destination="org.chromium.ImageLoader" />
+ </policy>
+ <policy user="chronos">
+ <allow receive_sender="org.chromium.ImageLoader" />
+ <allow send_destination="org.chromium.ImageLoader"
+ send_interface="org.chromium.ImageLoaderInterface"
+ send_member="RegisterComponent" />
+ <allow send_destination="org.chromium.ImageLoader"
+ send_interface="org.chromium.ImageLoaderInterface"
+ send_member="GetComponentVersion" />
+ <allow send_destination="org.chromium.ImageLoader"
+ send_interface="org.chromium.ImageLoaderInterface"
+ send_member="LoadComponent" />
+ <allow send_destination="org.chromium.ImageLoader"
+ send_interface="org.chromium.ImageLoaderInterface"
+ send_member="UnloadComponent" />
+ </policy>
+ <!-- deny others maybe? -->
+</busconfig>
diff --git a/org.chromium.ImageLoader.service b/org.chromium.ImageLoader.service
new file mode 100644
index 0000000..4806839
--- /dev/null
+++ b/org.chromium.ImageLoader.service
@@ -0,0 +1,7 @@
+# Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.i
+[D-BUS Service]
+Name=org.chromium.ImageLoader
+Exec=/usr/sbin/imageloader -o
+User=root
diff --git a/run_tests.cc b/run_tests.cc
new file mode 100644
index 0000000..451d8eb
--- /dev/null
+++ b/run_tests.cc
@@ -0,0 +1,10 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}