1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "gmock/gmock.h"
18 #include "update_engine/payload_consumer/postinstall_runner_action.h"
19
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include "common/dynamic_partition_control_interface.h"
28
29 #include <base/bind.h>
30 #include <base/files/file_util.h>
31 #include <base/message_loop/message_loop.h>
32 #include <android-base/stringprintf.h>
33 #include <brillo/message_loops/base_message_loop.h>
34 #include <brillo/message_loops/message_loop_utils.h>
35 #include <gmock/gmock.h>
36 #include <gtest/gtest.h>
37
38 #include "update_engine/common/fake_boot_control.h"
39 #include "update_engine/common/fake_hardware.h"
40 #include "update_engine/common/test_utils.h"
41 #include "update_engine/common/utils.h"
42 #include "update_engine/common/mock_dynamic_partition_control.h"
43
44 using brillo::MessageLoop;
45 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
46 using std::string;
47 using testing::_;
48 using testing::AtLeast;
49 using testing::Return;
50
51 namespace chromeos_update_engine {
52
53 class PostinstActionProcessorDelegate : public ActionProcessorDelegate {
54 public:
55 PostinstActionProcessorDelegate() = default;
ProcessingDone(const ActionProcessor * processor,ErrorCode code)56 void ProcessingDone(const ActionProcessor* processor,
57 ErrorCode code) override {
58 MessageLoop::current()->BreakLoop();
59 processing_done_called_ = true;
60 }
ProcessingStopped(const ActionProcessor * processor)61 void ProcessingStopped(const ActionProcessor* processor) override {
62 MessageLoop::current()->BreakLoop();
63 processing_stopped_called_ = true;
64 }
65
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)66 void ActionCompleted(ActionProcessor* processor,
67 AbstractAction* action,
68 ErrorCode code) override {
69 if (action->Type() == PostinstallRunnerAction::StaticType()) {
70 code_ = code;
71 code_set_ = true;
72 }
73 }
74
75 ErrorCode code_{ErrorCode::kError};
76 bool code_set_{false};
77 bool processing_done_called_{false};
78 bool processing_stopped_called_{false};
79 };
80
81 class MockPostinstallRunnerActionDelegate
82 : public PostinstallRunnerAction::DelegateInterface {
83 public:
84 MOCK_METHOD1(ProgressUpdate, void(double progress));
85 };
86
87 class PostinstallRunnerActionTest : public ::testing::Test {
88 protected:
SetUp()89 void SetUp() override {
90 loop_.SetAsCurrent();
91 {
92 auto mock_dynamic_control =
93 std::make_unique<MockDynamicPartitionControl>();
94 mock_dynamic_control_ = mock_dynamic_control.get();
95 fake_boot_control_.SetDynamicPartitionControl(
96 std::move(mock_dynamic_control));
97 }
98 ON_CALL(*mock_dynamic_control_, FinishUpdate(_))
99 .WillByDefault(Return(true));
100 ON_CALL(*mock_dynamic_control_, GetVirtualAbFeatureFlag())
101 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
102 }
103
104 // Setup an action processor and run the PostinstallRunnerAction with a single
105 // partition |device_path|, running the |postinstall_program| command from
106 // there.
107 void RunPostinstallAction(bool powerwash_required, bool save_rollback_data);
108
109 void RunPostinstallActionWithInstallPlan(const InstallPlan& install_plan);
110
111 public:
ResumeRunningAction()112 void ResumeRunningAction() {
113 ASSERT_NE(nullptr, postinstall_action_);
114 postinstall_action_->ResumeAction();
115 }
116
117 protected:
118 base::MessageLoopForIO base_loop_;
119 brillo::BaseMessageLoop loop_{&base_loop_};
120
121 FakeBootControl fake_boot_control_;
122 FakeHardware fake_hardware_;
123 MockDynamicPartitionControl* mock_dynamic_control_;
124 PostinstActionProcessorDelegate processor_delegate_;
125
126 // The PostinstallRunnerAction delegate receiving the progress updates.
127 PostinstallRunnerAction::DelegateInterface* setup_action_delegate_{nullptr};
128
129 // A pointer to the posinstall_runner action and the processor.
130 PostinstallRunnerAction* postinstall_action_{nullptr};
131 ActionProcessor* processor_{nullptr};
132 };
133
RunPostinstallAction(bool powerwash_required,bool save_rollback_data)134 void PostinstallRunnerActionTest::RunPostinstallAction(
135 bool powerwash_required, bool save_rollback_data) {
136 InstallPlan::Partition part;
137 part.name = "part";
138 part.target_path = "/dev/invalid";
139 part.readonly_target_path = "/dev/invalid";
140 part.run_postinstall = false;
141 part.postinstall_path.clear();
142 InstallPlan install_plan;
143 install_plan.partitions = {part};
144 install_plan.download_url = "http://127.0.0.1:8080/update";
145 install_plan.powerwash_required = powerwash_required;
146 RunPostinstallActionWithInstallPlan(install_plan);
147 }
148
RunPostinstallActionWithInstallPlan(const chromeos_update_engine::InstallPlan & install_plan)149 void PostinstallRunnerActionTest::RunPostinstallActionWithInstallPlan(
150 const chromeos_update_engine::InstallPlan& install_plan) {
151 ActionProcessor processor;
152 processor_ = &processor;
153 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
154 feeder_action->set_obj(install_plan);
155 auto runner_action = std::make_unique<PostinstallRunnerAction>(
156 &fake_boot_control_, &fake_hardware_);
157 postinstall_action_ = runner_action.get();
158 base::FilePath temp_dir;
159 TEST_AND_RETURN(base::CreateNewTempDirectory("postinstall", &temp_dir));
160 postinstall_action_->SetMountDir(temp_dir.value());
161 runner_action->set_delegate(setup_action_delegate_);
162 BondActions(feeder_action.get(), runner_action.get());
163 auto collector_action =
164 std::make_unique<ObjectCollectorAction<InstallPlan>>();
165 BondActions(runner_action.get(), collector_action.get());
166 processor.EnqueueAction(std::move(feeder_action));
167 processor.EnqueueAction(std::move(runner_action));
168 processor.EnqueueAction(std::move(collector_action));
169 processor.set_delegate(&processor_delegate_);
170
171 loop_.PostTask(
172 FROM_HERE,
173 base::Bind(
174 [](ActionProcessor* processor) { processor->StartProcessing(); },
175 base::Unretained(&processor)));
176 loop_.Run();
177 ASSERT_FALSE(processor.IsRunning());
178 postinstall_action_ = nullptr;
179 processor_ = nullptr;
180 ASSERT_TRUE(processor_delegate_.processing_stopped_called_ ||
181 processor_delegate_.processing_done_called_);
182 if (processor_delegate_.processing_done_called_) {
183 // Validation check that the code was set when the processor finishes.
184 ASSERT_TRUE(processor_delegate_.code_set_);
185 }
186 }
187
188 // Test that postinstall succeeds in the simple case of running the default
189 // /postinst command which only exits 0.
TEST_F(PostinstallRunnerActionTest,RunAsRootSimpleTest)190 TEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) {
191 EXPECT_CALL(*mock_dynamic_control_, GetVirtualAbFeatureFlag())
192 .WillOnce(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
193 RunPostinstallAction(false, false);
194 ASSERT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
195 ASSERT_TRUE(processor_delegate_.processing_done_called_);
196
197 // Since powerwash_required was false, this should not trigger a powerwash.
198 ASSERT_FALSE(fake_hardware_.IsPowerwashScheduled());
199 ASSERT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
200 }
201
202 } // namespace chromeos_update_engine
203