update_engine: support DLC update
All DLC update related code is hide behind USE_dlc flag so platform
update never touches this new code path unless enabled later.
In CheckForUpdate, update_engine calls dlcservice to get a list of DLC
module and set 'dlc_ids_' accordingly.
BUG=chromium:900653
TEST=unittest
Change-Id: I654e37effa7c1b70b25147a027f2b16abe6bf9e1
Reviewed-on: https://chromium-review.googlesource.com/1321009
Commit-Ready: Xiaochu Liu <xiaochu@chromium.org>
Tested-by: Xiaochu Liu <xiaochu@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
diff --git a/common/dlcservice.h b/common/dlcservice.h
new file mode 100644
index 0000000..9dae560
--- /dev/null
+++ b/common/dlcservice.h
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_COMMON_DLCSERVICE_H_
+#define UPDATE_ENGINE_COMMON_DLCSERVICE_H_
+
+#include <memory>
+
+#include "update_engine/common/dlcservice_interface.h"
+
+namespace chromeos_update_engine {
+
+// This factory function creates a new DlcServiceInterface instance for the
+// current platform.
+std::unique_ptr<DlcServiceInterface> CreateDlcService();
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_COMMON_DLCSERVICE_H_
diff --git a/common/dlcservice_interface.h b/common/dlcservice_interface.h
new file mode 100644
index 0000000..aa24105
--- /dev/null
+++ b/common/dlcservice_interface.h
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_COMMON_DLCSERVICE_INTERFACE_H_
+#define UPDATE_ENGINE_COMMON_DLCSERVICE_INTERFACE_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace chromeos_update_engine {
+
+// The abstract dlcservice interface defines the interaction with the
+// platform's dlcservice.
+class DlcServiceInterface {
+ public:
+ virtual ~DlcServiceInterface() = default;
+
+ // Returns true and a list of installed DLC module ids in |dlc_module_ids|.
+ // On failure it returns false.
+ virtual bool GetInstalled(std::vector<std::string>* dlc_module_ids) = 0;
+
+ protected:
+ DlcServiceInterface() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DlcServiceInterface);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_COMMON_DLCSERVICE_INTERFACE_H_
diff --git a/common/dlcservice_stub.cc b/common/dlcservice_stub.cc
new file mode 100644
index 0000000..c5f9306
--- /dev/null
+++ b/common/dlcservice_stub.cc
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/common/dlcservice_stub.h"
+
+#include <memory>
+
+using std::string;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+std::unique_ptr<DlcServiceInterface> CreateDlcService() {
+ return std::make_unique<DlcServiceStub>();
+}
+
+bool DlcServiceStub::GetInstalled(std::vector<std::string>* dlc_module_ids) {
+ if (dlc_module_ids)
+ dlc_module_ids->clear();
+ return true;
+}
+
+} // namespace chromeos_update_engine
diff --git a/common/dlcservice_stub.h b/common/dlcservice_stub.h
new file mode 100644
index 0000000..4e12c11
--- /dev/null
+++ b/common/dlcservice_stub.h
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_COMMON_DLCSERVICE_STUB_H_
+#define UPDATE_ENGINE_COMMON_DLCSERVICE_STUB_H_
+
+#include <string>
+#include <vector>
+
+#include "update_engine/common/dlcservice_interface.h"
+
+namespace chromeos_update_engine {
+
+// An implementation of the DlcServiceInterface that does nothing.
+class DlcServiceStub : public DlcServiceInterface {
+ public:
+ DlcServiceStub() = default;
+ ~DlcServiceStub() = default;
+
+ // BootControlInterface overrides.
+ bool GetInstalled(std::vector<std::string>* dlc_module_ids) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DlcServiceStub);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_COMMON_DLCSERVICE_STUB_H_
diff --git a/dlcservice_chromeos.cc b/dlcservice_chromeos.cc
new file mode 100644
index 0000000..e95f08f
--- /dev/null
+++ b/dlcservice_chromeos.cc
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/dlcservice_chromeos.h"
+
+#include <dlcservice/dbus-proxies.h>
+#include <dlcservice/proto_bindings/dlcservice.pb.h>
+
+#include "update_engine/dbus_connection.h"
+
+using std::string;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+std::unique_ptr<DlcServiceInterface> CreateDlcService() {
+ return std::make_unique<DlcServiceChromeOS>();
+}
+
+bool DlcServiceChromeOS::GetInstalled(vector<string>* dlc_module_ids) {
+ if (!dlc_module_ids)
+ return false;
+ org::chromium::DlcServiceInterfaceProxy dlcservice_proxy(
+ DBusConnection::Get()->GetDBus());
+ string dlc_module_list_str;
+ if (!dlcservice_proxy.GetInstalled(&dlc_module_list_str, nullptr)) {
+ LOG(ERROR) << "dlcservice does not return installed DLC module list.";
+ return false;
+ }
+ dlcservice::DlcModuleList dlc_module_list;
+ if (!dlc_module_list.ParseFromString(dlc_module_list_str)) {
+ LOG(ERROR) << "Errors parsing DlcModuleList protobuf.";
+ return false;
+ }
+ for (const auto& dlc_module_info : dlc_module_list.dlc_module_infos()) {
+ dlc_module_ids->emplace_back(dlc_module_info.dlc_id());
+ }
+ return true;
+}
+
+} // namespace chromeos_update_engine
diff --git a/dlcservice_chromeos.h b/dlcservice_chromeos.h
new file mode 100644
index 0000000..8d103c1
--- /dev/null
+++ b/dlcservice_chromeos.h
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_DLCSERVICE_CHROMEOS_H_
+#define UPDATE_ENGINE_DLCSERVICE_CHROMEOS_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "update_engine/common/dlcservice_interface.h"
+
+namespace chromeos_update_engine {
+
+// The Chrome OS implementation of the DlcServiceInterface. This interface
+// interacts with dlcservice via D-Bus.
+class DlcServiceChromeOS : public DlcServiceInterface {
+ public:
+ DlcServiceChromeOS() = default;
+ ~DlcServiceChromeOS() = default;
+
+ // BootControlInterface overrides.
+ bool GetInstalled(std::vector<std::string>* dlc_module_ids) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DlcServiceChromeOS);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_DLCSERVICE_CHROMEOS_H_
diff --git a/fake_system_state.h b/fake_system_state.h
index 67ad3aa..627bd5c 100644
--- a/fake_system_state.h
+++ b/fake_system_state.h
@@ -100,6 +100,8 @@
return power_manager_;
}
+ inline DlcServiceInterface* dlcservice() override { return dlcservice_; }
+
inline bool system_rebooted() override { return fake_system_rebooted_; }
// Setters for the various members, can be used for overriding the default
@@ -165,6 +167,10 @@
fake_system_rebooted_ = system_rebooted;
}
+ inline void set_dlcservice(DlcServiceInterface* dlcservice) {
+ dlcservice_ = dlcservice;
+ }
+
// Getters for the built-in default implementations. These return the actual
// concrete type of each implementation. For additional safety, they will fail
// whenever the requested default was overridden by a different
@@ -261,6 +267,7 @@
P2PManager* p2p_manager_;
chromeos_update_manager::UpdateManager* update_manager_;
PowerManagerInterface* power_manager_{&mock_power_manager_};
+ DlcServiceInterface* dlcservice_;
// Other object pointers (not preinitialized).
const policy::DevicePolicy* device_policy_;
diff --git a/real_system_state.cc b/real_system_state.cc
index 9dab3a1..f576c6c 100644
--- a/real_system_state.cc
+++ b/real_system_state.cc
@@ -32,6 +32,7 @@
#include "update_engine/common/boot_control.h"
#include "update_engine/common/boot_control_stub.h"
#include "update_engine/common/constants.h"
+#include "update_engine/common/dlcservice.h"
#include "update_engine/common/hardware.h"
#include "update_engine/common/utils.h"
#include "update_engine/metrics_reporter_omaha.h"
@@ -88,6 +89,12 @@
return false;
}
+ dlcservice_ = CreateDlcService();
+ if (!dlcservice_) {
+ LOG(ERROR) << "Error initializing the DlcServiceInterface.";
+ return false;
+ }
+
// Initialize standard and powerwash-safe prefs.
base::FilePath non_volatile_path;
// TODO(deymo): Fall back to in-memory prefs if there's no physical directory
diff --git a/real_system_state.h b/real_system_state.h
index 5239160..4712008 100644
--- a/real_system_state.h
+++ b/real_system_state.h
@@ -31,6 +31,7 @@
#include "update_engine/certificate_checker.h"
#include "update_engine/common/boot_control_interface.h"
#include "update_engine/common/clock.h"
+#include "update_engine/common/dlcservice_interface.h"
#include "update_engine/common/hardware_interface.h"
#include "update_engine/common/prefs.h"
#include "update_engine/connection_manager_interface.h"
@@ -126,6 +127,10 @@
inline bool system_rebooted() override { return system_rebooted_; }
+ inline DlcServiceInterface* dlcservice() override {
+ return dlcservice_.get();
+ }
+
private:
// Real DBus proxies using the DBus connection.
#if USE_CHROME_KIOSK_APP
@@ -136,6 +141,9 @@
// Interface for the power manager.
std::unique_ptr<PowerManagerInterface> power_manager_;
+ // Interface for dlcservice.
+ std::unique_ptr<DlcServiceInterface> dlcservice_;
+
// Interface for the clock.
std::unique_ptr<BootControlInterface> boot_control_;
diff --git a/system_state.h b/system_state.h
index 1b0ad08..f46cbcf 100644
--- a/system_state.h
+++ b/system_state.h
@@ -37,6 +37,7 @@
class BootControlInterface;
class ClockInterface;
class ConnectionManagerInterface;
+class DlcServiceInterface;
class HardwareInterface;
class MetricsReporterInterface;
class OmahaRequestParams;
@@ -109,6 +110,9 @@
// restarted. Important for tracking whether you are running instance of the
// update engine on first boot or due to a crash/restart.
virtual bool system_rebooted() = 0;
+
+ // Returns a pointer to the DlcServiceInterface singleton.
+ virtual DlcServiceInterface* dlcservice() = 0;
};
} // namespace chromeos_update_engine
diff --git a/update_attempter.cc b/update_attempter.cc
index 581b901..f1ec174 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -44,6 +44,7 @@
#include "update_engine/common/boot_control_interface.h"
#include "update_engine/common/clock_interface.h"
#include "update_engine/common/constants.h"
+#include "update_engine/common/dlcservice_interface.h"
#include "update_engine/common/hardware_interface.h"
#include "update_engine/common/platform_constants.h"
#include "update_engine/common/prefs_interface.h"
@@ -840,6 +841,9 @@
}
if (forced_update_pending_callback_.get()) {
+ if (!system_state_->dlcservice()->GetInstalled(&dlc_ids_)) {
+ dlc_ids_.clear();
+ }
// Make sure that a scheduling request is made prior to calling the forced
// update pending callback.
ScheduleUpdates();
diff --git a/update_attempter.h b/update_attempter.h
index ebbd5ec..2d020fa 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -266,6 +266,7 @@
FRIEND_TEST(UpdateAttempterTest, BootTimeInUpdateMarkerFile);
FRIEND_TEST(UpdateAttempterTest, BroadcastCompleteDownloadTest);
FRIEND_TEST(UpdateAttempterTest, ChangeToDownloadingOnReceivedBytesTest);
+ FRIEND_TEST(UpdateAttempterTest, CheckForUpdateAUDlcTest);
FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventTest);
FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventResumedTest);
FRIEND_TEST(UpdateAttempterTest, DisableDeltaUpdateIfNeededTest);
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 0e1be2c..8fe2cb9 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -31,6 +31,7 @@
#include <policy/mock_device_policy.h>
#include <policy/mock_libpolicy.h>
+#include "update_engine/common/dlcservice_interface.h"
#include "update_engine/common/fake_clock.h"
#include "update_engine/common/fake_prefs.h"
#include "update_engine/common/mock_action.h"
@@ -79,6 +80,15 @@
namespace chromeos_update_engine {
+namespace {
+
+class MockDlcService : public DlcServiceInterface {
+ public:
+ MOCK_METHOD1(GetInstalled, bool(vector<string>*));
+};
+
+} // namespace
+
const char kRollbackVersion[] = "10575.39.2";
// Test a subclass rather than the main class directly so that we can mock out
@@ -122,10 +132,13 @@
// Override system state members.
fake_system_state_.set_connection_manager(&mock_connection_manager);
fake_system_state_.set_update_attempter(&attempter_);
+ fake_system_state_.set_dlcservice(&mock_dlcservice_);
loop_.SetAsCurrent();
certificate_checker_.Init();
+ attempter_.set_forced_update_pending_callback(
+ new base::Callback<void(bool, bool)>(base::Bind([](bool, bool) {})));
// Finish initializing the attempter.
attempter_.Init();
}
@@ -200,6 +213,7 @@
UpdateAttempterUnderTest attempter_{&fake_system_state_};
OpenSSLWrapper openssl_wrapper_;
CertificateChecker certificate_checker_;
+ MockDlcService mock_dlcservice_;
NiceMock<MockActionProcessor>* processor_;
NiceMock<MockPrefs>* prefs_; // Shortcut to fake_system_state_->mock_prefs().
@@ -1161,6 +1175,21 @@
EXPECT_FALSE(attempter_.IsAnyUpdateSourceAllowed());
}
+TEST_F(UpdateAttempterTest, CheckForUpdateAUDlcTest) {
+ fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
+ fake_system_state_.fake_hardware()->SetAreDevFeaturesEnabled(false);
+
+ const string dlc_module_id = "a_dlc_module_id";
+ vector<string> dlc_module_ids = {dlc_module_id};
+ ON_CALL(mock_dlcservice_, GetInstalled(testing::_))
+ .WillByDefault(DoAll(testing::SetArgPointee<0>(dlc_module_ids),
+ testing::Return(true)));
+
+ attempter_.CheckForUpdate("", "autest", UpdateAttemptFlags::kNone);
+ EXPECT_EQ(attempter_.dlc_ids_.size(), 1);
+ EXPECT_EQ(attempter_.dlc_ids_[0], dlc_module_id);
+}
+
TEST_F(UpdateAttempterTest, CheckForUpdateAUTest) {
fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
fake_system_state_.fake_hardware()->SetAreDevFeaturesEnabled(false);
diff --git a/update_engine.gyp b/update_engine.gyp
index 7621153..c9e05d8 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -223,6 +223,13 @@
'libupdate_engine-client',
'vboot_host',
],
+ 'conditions':[
+ ['USE_dlc == 1', {
+ 'exported_deps' : [
+ 'libdlcservice-client',
+ ],
+ }],
+ ],
'deps': ['<@(exported_deps)'],
},
'all_dependent_settings': {
@@ -308,6 +315,16 @@
'update_engine-dbus-kiosk-app-client',
],
}],
+ ['USE_dlc == 1', {
+ 'sources': [
+ 'dlcservice_chromeos.cc',
+ ],
+ }],
+ ['USE_dlc == 0', {
+ 'sources': [
+ 'common/dlcservice_stub.cc',
+ ],
+ }],
],
},
# update_engine daemon.