blob: e44af157e37bee47522862f1b99ec4ccaa172d83 [file] [log] [blame]
Yifan Hong537802d2018-08-15 13:15:42 -07001//
2// Copyright (C) 2018 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 "update_engine/boot_control_android.h"
18
19#include <set>
Yifan Hongd4db07e2018-10-18 17:46:27 -070020#include <vector>
Yifan Hong537802d2018-08-15 13:15:42 -070021
Yifan Hongd4db07e2018-10-18 17:46:27 -070022#include <base/logging.h>
23#include <base/strings/string_util.h>
David Andersond63cb3c2018-10-01 14:15:00 -070024#include <fs_mgr.h>
Yifan Hong537802d2018-08-15 13:15:42 -070025#include <gmock/gmock.h>
26#include <gtest/gtest.h>
Yifan Hong1d9077f2018-12-07 12:09:37 -080027#include <libdm/dm.h>
Yifan Hong537802d2018-08-15 13:15:42 -070028
Yifan Hongc049f932019-07-23 15:06:05 -070029#include "update_engine/dynamic_partition_test_utils.h"
Yifan Hong537802d2018-08-15 13:15:42 -070030#include "update_engine/mock_boot_control_hal.h"
31#include "update_engine/mock_dynamic_partition_control.h"
32
Yifan Hong1d9077f2018-12-07 12:09:37 -080033using android::dm::DmDeviceState;
Yifan Hong537802d2018-08-15 13:15:42 -070034using android::hardware::Void;
Dan Albertfcfbda22018-12-14 12:57:55 -080035using std::string;
Yifan Hong537802d2018-08-15 13:15:42 -070036using testing::_;
37using testing::AnyNumber;
Yifan Hong537802d2018-08-15 13:15:42 -070038using testing::Invoke;
Yifan Hong537802d2018-08-15 13:15:42 -070039using testing::NiceMock;
Yifan Hongd4db07e2018-10-18 17:46:27 -070040using testing::Not;
Yifan Hong537802d2018-08-15 13:15:42 -070041using testing::Return;
42
43namespace chromeos_update_engine {
44
Yifan Hong537802d2018-08-15 13:15:42 -070045class BootControlAndroidTest : public ::testing::Test {
46 protected:
47 void SetUp() override {
48 // Fake init bootctl_
49 bootctl_.module_ = new NiceMock<MockBootControlHal>();
50 bootctl_.dynamic_control_ =
Yifan Hongc049f932019-07-23 15:06:05 -070051 std::make_unique<NiceMock<MockDynamicPartitionControl>>();
Yifan Hong537802d2018-08-15 13:15:42 -070052
53 ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] {
54 return kMaxNumSlots;
55 }));
56 ON_CALL(module(), getSuffix(_, _))
57 .WillByDefault(Invoke([](auto slot, auto cb) {
58 EXPECT_LE(slot, kMaxNumSlots);
59 cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : "");
60 return Void();
61 }));
62
Yifan Hong186bb682019-07-23 14:04:39 -070063 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
64 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
Yifan Hong413d5722019-07-23 14:21:09 -070065 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
66 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
Yifan Hong1d9077f2018-12-07 12:09:37 -080067 ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true));
Yifan Hong537802d2018-08-15 13:15:42 -070068 ON_CALL(dynamicControl(), GetDeviceDir(_))
69 .WillByDefault(Invoke([](auto path) {
70 *path = kFakeDevicePath;
71 return true;
72 }));
Yifan Hong1d9077f2018-12-07 12:09:37 -080073 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
74 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
75 *device = GetDmDevice(partition_name_suffix);
76 return true;
77 }));
Yifan Hong700d7c12019-07-23 20:49:16 -070078
79 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
80 .WillByDefault(Return(kFakeSuper));
81 }
82
83 std::string GetSuperDevice(uint32_t slot) {
84 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
Yifan Hong537802d2018-08-15 13:15:42 -070085 }
86
87 // Return the mocked HAL module.
88 NiceMock<MockBootControlHal>& module() {
89 return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
90 }
91
92 // Return the mocked DynamicPartitionControlInterface.
Yifan Hongc049f932019-07-23 15:06:05 -070093 NiceMock<MockDynamicPartitionControl>& dynamicControl() {
94 return static_cast<NiceMock<MockDynamicPartitionControl>&>(
Yifan Hong537802d2018-08-15 13:15:42 -070095 *bootctl_.dynamic_control_);
96 }
97
98 // Set the fake metadata to return when LoadMetadataBuilder is called on
99 // |slot|.
Yifan Hongd4db07e2018-10-18 17:46:27 -0700100 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
Yifan Hong6e706b12018-11-09 16:50:51 -0800101 EXPECT_CALL(dynamicControl(),
Yifan Hongc049f932019-07-23 15:06:05 -0700102 LoadMetadataBuilder(GetSuperDevice(slot), slot))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700103 .Times(AnyNumber())
Yifan Hongc049f932019-07-23 15:06:05 -0700104 .WillRepeatedly(Invoke([sizes](auto, auto) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700105 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
Yifan Hong6e706b12018-11-09 16:50:51 -0800106 }));
Yifan Hong537802d2018-08-15 13:15:42 -0700107 }
108
Yifan Hong537802d2018-08-15 13:15:42 -0700109 uint32_t source() { return slots_.source; }
110
111 uint32_t target() { return slots_.target; }
112
113 // Return partition names with suffix of source().
Dan Albertfcfbda22018-12-14 12:57:55 -0800114 string S(const string& name) { return name + kSlotSuffixes[source()]; }
Yifan Hong537802d2018-08-15 13:15:42 -0700115
116 // Return partition names with suffix of target().
Dan Albertfcfbda22018-12-14 12:57:55 -0800117 string T(const string& name) { return name + kSlotSuffixes[target()]; }
Yifan Hong537802d2018-08-15 13:15:42 -0700118
119 // Set source and target slots to use before testing.
120 void SetSlots(const TestParam& slots) {
121 slots_ = slots;
122
123 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
124 return source();
125 }));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700126 }
127
Yifan Hong13d41cb2019-09-16 13:18:22 -0700128 bool PreparePartitionsForUpdate(uint32_t slot,
129 PartitionSizes partition_sizes,
130 bool update_metadata = true) {
131 auto m = PartitionSizesToManifest(partition_sizes);
132 return bootctl_.PreparePartitionsForUpdate(slot, m, update_metadata);
Yifan Hong537802d2018-08-15 13:15:42 -0700133 }
134
135 BootControlAndroid bootctl_; // BootControlAndroid under test.
136 TestParam slots_;
Yifan Hong537802d2018-08-15 13:15:42 -0700137};
138
139class BootControlAndroidTestP
140 : public BootControlAndroidTest,
141 public ::testing::WithParamInterface<TestParam> {
142 public:
143 void SetUp() override {
144 BootControlAndroidTest::SetUp();
145 SetSlots(GetParam());
146 }
147};
148
Yifan Hong1d9077f2018-12-07 12:09:37 -0800149// Test applying retrofit update on a build with dynamic partitions enabled.
150TEST_P(BootControlAndroidTestP,
151 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
152 SetMetadata(source(),
153 {{S("system"), 2_GiB},
154 {S("vendor"), 1_GiB},
155 {T("system"), 2_GiB},
156 {T("vendor"), 1_GiB}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800157
Yifan Hong13d41cb2019-09-16 13:18:22 -0700158 // Not calling through BootControlAndroidTest::PreparePartitionsForUpdate(),
159 // since we don't want any default group in the PartitionMetadata.
160 EXPECT_TRUE(bootctl_.PreparePartitionsForUpdate(target(), {}, true));
Yifan Hong1d9077f2018-12-07 12:09:37 -0800161
162 // Should use dynamic source partitions.
163 EXPECT_CALL(dynamicControl(), GetState(S("system")))
164 .Times(1)
165 .WillOnce(Return(DmDeviceState::ACTIVE));
Tao Bao3406c772019-01-02 15:34:35 -0800166 string system_device;
167 EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device));
168 EXPECT_EQ(GetDmDevice(S("system")), system_device);
Yifan Hong1d9077f2018-12-07 12:09:37 -0800169
170 // Should use static target partitions without querying dynamic control.
171 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
Tao Bao3406c772019-01-02 15:34:35 -0800172 EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device));
173 EXPECT_EQ(GetDevice(T("system")), system_device);
174
175 // Static partition "bar".
176 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
177 std::string bar_device;
178 EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device));
179 EXPECT_EQ(GetDevice(S("bar")), bar_device);
180
181 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
182 EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device));
183 EXPECT_EQ(GetDevice(T("bar")), bar_device);
184}
185
186TEST_P(BootControlAndroidTestP, GetPartitionDeviceWhenResumingUpdate) {
187 // Both of the two slots contain valid partition metadata, since this is
188 // resuming an update.
189 SetMetadata(source(),
190 {{S("system"), 2_GiB},
191 {S("vendor"), 1_GiB},
192 {T("system"), 2_GiB},
193 {T("vendor"), 1_GiB}});
194 SetMetadata(target(),
195 {{S("system"), 2_GiB},
196 {S("vendor"), 1_GiB},
197 {T("system"), 2_GiB},
198 {T("vendor"), 1_GiB}});
Yifan Hongc049f932019-07-23 15:06:05 -0700199
Yifan Hongf0f4a912019-09-26 17:51:33 -0700200 EXPECT_CALL(dynamicControl(), PreparePartitionsForUpdate(_, _, _, false))
201 .WillOnce(Return(true));
202
Yifan Hong13d41cb2019-09-16 13:18:22 -0700203 EXPECT_TRUE(PreparePartitionsForUpdate(
Tao Bao3406c772019-01-02 15:34:35 -0800204 target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}, false));
205
206 // Dynamic partition "system".
207 EXPECT_CALL(dynamicControl(), GetState(S("system")))
208 .Times(1)
209 .WillOnce(Return(DmDeviceState::ACTIVE));
210 string system_device;
211 EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device));
212 EXPECT_EQ(GetDmDevice(S("system")), system_device);
213
214 EXPECT_CALL(dynamicControl(), GetState(T("system")))
Yifan Hong8546a712019-03-28 14:42:53 -0700215 .Times(AnyNumber())
Tao Bao3406c772019-01-02 15:34:35 -0800216 .WillOnce(Return(DmDeviceState::ACTIVE));
Yifan Hong8546a712019-03-28 14:42:53 -0700217 EXPECT_CALL(dynamicControl(),
218 MapPartitionOnDeviceMapper(
219 GetSuperDevice(target()), T("system"), target(), _, _))
220 .Times(AnyNumber())
221 .WillRepeatedly(
222 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
223 *device = "/fake/remapped/" + name;
224 return true;
225 }));
Tao Bao3406c772019-01-02 15:34:35 -0800226 EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device));
Yifan Hong8546a712019-03-28 14:42:53 -0700227 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
Tao Bao3406c772019-01-02 15:34:35 -0800228
229 // Static partition "bar".
230 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
231 std::string bar_device;
232 EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device));
233 EXPECT_EQ(GetDevice(S("bar")), bar_device);
234
235 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
236 EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device));
237 EXPECT_EQ(GetDevice(T("bar")), bar_device);
Yifan Hong1d9077f2018-12-07 12:09:37 -0800238}
239
Yifan Hongd4db07e2018-10-18 17:46:27 -0700240INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
Yifan Hong537802d2018-08-15 13:15:42 -0700241 BootControlAndroidTestP,
242 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
243
Yifan Hong537802d2018-08-15 13:15:42 -0700244TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
245 SetSlots({1, 1});
Yifan Hong13d41cb2019-09-16 13:18:22 -0700246 EXPECT_FALSE(PreparePartitionsForUpdate(target(), {}))
Yifan Hong537802d2018-08-15 13:15:42 -0700247 << "Should not be able to apply to current slot.";
248}
249
Yifan Hong537802d2018-08-15 13:15:42 -0700250} // namespace chromeos_update_engine