xref: /aosp_15_r20/system/extras/tests/bootloader/bootloadertest.py (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2016 The Android Open Source Project
2*288bf522SAndroid Build Coastguard Worker#
3*288bf522SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*288bf522SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*288bf522SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*288bf522SAndroid Build Coastguard Worker#
7*288bf522SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
8*288bf522SAndroid Build Coastguard Worker#
9*288bf522SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*288bf522SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*288bf522SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*288bf522SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*288bf522SAndroid Build Coastguard Worker# limitations under the License.
14*288bf522SAndroid Build Coastguard Worker
15*288bf522SAndroid Build Coastguard Workerfrom __future__ import print_function
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Workerimport argparse
18*288bf522SAndroid Build Coastguard Workerimport os
19*288bf522SAndroid Build Coastguard Workerimport unittest
20*288bf522SAndroid Build Coastguard Workerimport fastboot
21*288bf522SAndroid Build Coastguard Workerimport subprocess
22*288bf522SAndroid Build Coastguard Workerimport sys
23*288bf522SAndroid Build Coastguard Worker
24*288bf522SAndroid Build Coastguard Worker# Default values for arguments
25*288bf522SAndroid Build Coastguard Workerdevice_type = "phone"
26*288bf522SAndroid Build Coastguard Worker
27*288bf522SAndroid Build Coastguard Workerclass ShellTest(unittest.TestCase):
28*288bf522SAndroid Build Coastguard Worker    @classmethod
29*288bf522SAndroid Build Coastguard Worker    def setUpClass(cls):
30*288bf522SAndroid Build Coastguard Worker        cls.fastboot = fastboot.FastbootDevice()
31*288bf522SAndroid Build Coastguard Worker
32*288bf522SAndroid Build Coastguard Worker    def exists_validvals(self, varname, varlist, validlist):
33*288bf522SAndroid Build Coastguard Worker        self.assertIn(varname, varlist)
34*288bf522SAndroid Build Coastguard Worker        self.assertIn(varlist[varname], validlist)
35*288bf522SAndroid Build Coastguard Worker        return varlist[varname]
36*288bf522SAndroid Build Coastguard Worker
37*288bf522SAndroid Build Coastguard Worker    def exists_yes_no(self, varname, varlist):
38*288bf522SAndroid Build Coastguard Worker        return self.exists_validvals(varname, varlist, ["yes", "no"])
39*288bf522SAndroid Build Coastguard Worker
40*288bf522SAndroid Build Coastguard Worker    def exists_nonempty(self, varname, varlist):
41*288bf522SAndroid Build Coastguard Worker        self.assertIn(varname, varlist)
42*288bf522SAndroid Build Coastguard Worker        self.assertGreater(len(varlist[varname]), 0)
43*288bf522SAndroid Build Coastguard Worker        return varlist[varname]
44*288bf522SAndroid Build Coastguard Worker
45*288bf522SAndroid Build Coastguard Worker    def exists_integer(self, varname, varlist, base=10):
46*288bf522SAndroid Build Coastguard Worker        val = 0
47*288bf522SAndroid Build Coastguard Worker        self.assertIn(varname, varlist)
48*288bf522SAndroid Build Coastguard Worker        try:
49*288bf522SAndroid Build Coastguard Worker            val = int(varlist[varname], base)
50*288bf522SAndroid Build Coastguard Worker        except ValueError:
51*288bf522SAndroid Build Coastguard Worker            self.fail("%s (%s) is not an integer" % (varname, varlist[varname]))
52*288bf522SAndroid Build Coastguard Worker        return val
53*288bf522SAndroid Build Coastguard Worker
54*288bf522SAndroid Build Coastguard Worker    def get_exists(self, varname):
55*288bf522SAndroid Build Coastguard Worker        val = self.fastboot.getvar(varname)
56*288bf522SAndroid Build Coastguard Worker        self.assertIsNotNone(val)
57*288bf522SAndroid Build Coastguard Worker        return val
58*288bf522SAndroid Build Coastguard Worker
59*288bf522SAndroid Build Coastguard Worker    def get_exists_validvals(self, varname, validlist):
60*288bf522SAndroid Build Coastguard Worker        val = self.get_exists(varname)
61*288bf522SAndroid Build Coastguard Worker        self.assertIn(val, validlist)
62*288bf522SAndroid Build Coastguard Worker        return val
63*288bf522SAndroid Build Coastguard Worker
64*288bf522SAndroid Build Coastguard Worker    def get_exists_yes_no(self, varname):
65*288bf522SAndroid Build Coastguard Worker        return self.get_exists_validvals(varname, ["yes", "no"])
66*288bf522SAndroid Build Coastguard Worker
67*288bf522SAndroid Build Coastguard Worker    def get_exists_nonempty(self, varname):
68*288bf522SAndroid Build Coastguard Worker        val = self.get_exists(varname)
69*288bf522SAndroid Build Coastguard Worker        self.assertGreater(len(val), 0)
70*288bf522SAndroid Build Coastguard Worker        return val
71*288bf522SAndroid Build Coastguard Worker
72*288bf522SAndroid Build Coastguard Worker    def get_exists_integer(self, varname, base=10):
73*288bf522SAndroid Build Coastguard Worker        val = self.get_exists(varname)
74*288bf522SAndroid Build Coastguard Worker        try:
75*288bf522SAndroid Build Coastguard Worker            num = int(val, base)
76*288bf522SAndroid Build Coastguard Worker        except ValueError:
77*288bf522SAndroid Build Coastguard Worker            self.fail("%s (%s) is not an integer" % (varname, val))
78*288bf522SAndroid Build Coastguard Worker        return num
79*288bf522SAndroid Build Coastguard Worker
80*288bf522SAndroid Build Coastguard Worker    def get_slotcount(self):
81*288bf522SAndroid Build Coastguard Worker        slotcount = 0
82*288bf522SAndroid Build Coastguard Worker        try:
83*288bf522SAndroid Build Coastguard Worker            val = self.fastboot.getvar("slot-count")
84*288bf522SAndroid Build Coastguard Worker            if val != None:
85*288bf522SAndroid Build Coastguard Worker                slotcount = int(val)
86*288bf522SAndroid Build Coastguard Worker        except ValueError:
87*288bf522SAndroid Build Coastguard Worker            self.fail("slot-count (%s) is not an integer" % val)
88*288bf522SAndroid Build Coastguard Worker        except subprocess.CalledProcessError:
89*288bf522SAndroid Build Coastguard Worker            print("Does not appear to be an A/B device.")
90*288bf522SAndroid Build Coastguard Worker        if not slotcount:
91*288bf522SAndroid Build Coastguard Worker            print("Does not appear to be an A/B device.")
92*288bf522SAndroid Build Coastguard Worker        return slotcount
93*288bf522SAndroid Build Coastguard Worker
94*288bf522SAndroid Build Coastguard Worker    def test_getvarall(self):
95*288bf522SAndroid Build Coastguard Worker        """Tests that required variables are reported by getvar all"""
96*288bf522SAndroid Build Coastguard Worker
97*288bf522SAndroid Build Coastguard Worker        var_all = self.fastboot.getvar_all()
98*288bf522SAndroid Build Coastguard Worker        self.exists_nonempty("version-baseband", var_all)
99*288bf522SAndroid Build Coastguard Worker        self.exists_nonempty("version-bootloader", var_all)
100*288bf522SAndroid Build Coastguard Worker        self.exists_nonempty("product", var_all)
101*288bf522SAndroid Build Coastguard Worker        self.exists_yes_no("secure", var_all)
102*288bf522SAndroid Build Coastguard Worker        self.exists_yes_no("unlocked", var_all)
103*288bf522SAndroid Build Coastguard Worker        self.exists_validvals("off-mode-charge", var_all, ["0", "1"])
104*288bf522SAndroid Build Coastguard Worker        self.assertIn("variant", var_all)
105*288bf522SAndroid Build Coastguard Worker        voltage = self.exists_nonempty("battery-voltage", var_all)
106*288bf522SAndroid Build Coastguard Worker        if voltage[-2:].lower() == "mv":
107*288bf522SAndroid Build Coastguard Worker            voltage = voltage[:-2]
108*288bf522SAndroid Build Coastguard Worker        try:
109*288bf522SAndroid Build Coastguard Worker            voltnum = float(voltage)
110*288bf522SAndroid Build Coastguard Worker        except ValueError:
111*288bf522SAndroid Build Coastguard Worker            self.fail("battery-voltage (%s) is not a number" % (varname, voltage))
112*288bf522SAndroid Build Coastguard Worker        self.exists_yes_no("battery-soc-ok", var_all)
113*288bf522SAndroid Build Coastguard Worker        maxdl = self.exists_integer("max-download-size", var_all, 16)
114*288bf522SAndroid Build Coastguard Worker        self.assertGreater(maxdl, 0)
115*288bf522SAndroid Build Coastguard Worker
116*288bf522SAndroid Build Coastguard Worker        if "slot-count" in var_all:
117*288bf522SAndroid Build Coastguard Worker            try:
118*288bf522SAndroid Build Coastguard Worker                slotcount = int(var_all["slot-count"])
119*288bf522SAndroid Build Coastguard Worker            except ValueError:
120*288bf522SAndroid Build Coastguard Worker                self.fail("slot-count (%s) is not an integer" % var_all["slot-count"])
121*288bf522SAndroid Build Coastguard Worker            if slotcount > 1:
122*288bf522SAndroid Build Coastguard Worker                # test for A/B variables
123*288bf522SAndroid Build Coastguard Worker                slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
124*288bf522SAndroid Build Coastguard Worker                self.exists_validvals("current-slot", var_all, slots)
125*288bf522SAndroid Build Coastguard Worker
126*288bf522SAndroid Build Coastguard Worker                # test for slot metadata
127*288bf522SAndroid Build Coastguard Worker                for slot in slots:
128*288bf522SAndroid Build Coastguard Worker                    self.exists_yes_no("slot-unbootable:"+slot, var_all)
129*288bf522SAndroid Build Coastguard Worker                    self.exists_yes_no("slot-unbootable:"+slot, var_all)
130*288bf522SAndroid Build Coastguard Worker                    self.exists_integer("slot-retry-count:"+slot, var_all)
131*288bf522SAndroid Build Coastguard Worker            else:
132*288bf522SAndroid Build Coastguard Worker                print("This does not appear to be an A/B device.")
133*288bf522SAndroid Build Coastguard Worker
134*288bf522SAndroid Build Coastguard Worker    def test_getvar_nonexistent(self):
135*288bf522SAndroid Build Coastguard Worker        """Tests behaviour of nonexistent variables."""
136*288bf522SAndroid Build Coastguard Worker
137*288bf522SAndroid Build Coastguard Worker        self.assertIsNone(self.fastboot.getvar("fhqwhgads"))
138*288bf522SAndroid Build Coastguard Worker
139*288bf522SAndroid Build Coastguard Worker    def test_getvar(self):
140*288bf522SAndroid Build Coastguard Worker        """Tests all variables separately"""
141*288bf522SAndroid Build Coastguard Worker
142*288bf522SAndroid Build Coastguard Worker        self.get_exists_nonempty("version-baseband")
143*288bf522SAndroid Build Coastguard Worker        self.get_exists_nonempty("version-bootloader")
144*288bf522SAndroid Build Coastguard Worker        self.get_exists_nonempty("product")
145*288bf522SAndroid Build Coastguard Worker        self.get_exists_yes_no("secure")
146*288bf522SAndroid Build Coastguard Worker        self.get_exists_yes_no("unlocked")
147*288bf522SAndroid Build Coastguard Worker        self.get_exists_validvals("off-mode-charge", ["0", "1"])
148*288bf522SAndroid Build Coastguard Worker        self.get_exists("variant")
149*288bf522SAndroid Build Coastguard Worker        voltage = self.get_exists_nonempty("battery-voltage")
150*288bf522SAndroid Build Coastguard Worker        if voltage[-2:].lower() == "mv":
151*288bf522SAndroid Build Coastguard Worker            voltage = voltage[:-2]
152*288bf522SAndroid Build Coastguard Worker        try:
153*288bf522SAndroid Build Coastguard Worker            voltnum = float(voltage)
154*288bf522SAndroid Build Coastguard Worker        except ValueError:
155*288bf522SAndroid Build Coastguard Worker            self.fail("battery-voltage (%s) is not a number" % voltage)
156*288bf522SAndroid Build Coastguard Worker        self.get_exists_yes_no("battery-soc-ok")
157*288bf522SAndroid Build Coastguard Worker        maxdl = self.get_exists_integer("max-download-size", 16)
158*288bf522SAndroid Build Coastguard Worker        self.assertGreater(maxdl, 0)
159*288bf522SAndroid Build Coastguard Worker
160*288bf522SAndroid Build Coastguard Worker        slotcount = self.get_slotcount()
161*288bf522SAndroid Build Coastguard Worker        if slotcount  > 1:
162*288bf522SAndroid Build Coastguard Worker            # test for A/B variables
163*288bf522SAndroid Build Coastguard Worker            slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
164*288bf522SAndroid Build Coastguard Worker            self.get_exists_validvals("current-slot", slots)
165*288bf522SAndroid Build Coastguard Worker
166*288bf522SAndroid Build Coastguard Worker            # test for slot metadata
167*288bf522SAndroid Build Coastguard Worker            for slot in slots:
168*288bf522SAndroid Build Coastguard Worker                self.get_exists_yes_no("slot-unbootable:"+slot)
169*288bf522SAndroid Build Coastguard Worker                self.get_exists_yes_no("slot-successful:"+slot)
170*288bf522SAndroid Build Coastguard Worker                self.get_exists_integer("slot-retry-count:"+slot)
171*288bf522SAndroid Build Coastguard Worker
172*288bf522SAndroid Build Coastguard Worker    def test_setactive(self):
173*288bf522SAndroid Build Coastguard Worker        """Tests that A/B devices can switch to each slot, and the change persists over a reboot."""
174*288bf522SAndroid Build Coastguard Worker        # Test invalid if not an A/B device
175*288bf522SAndroid Build Coastguard Worker        slotcount = self.get_slotcount()
176*288bf522SAndroid Build Coastguard Worker        if not slotcount:
177*288bf522SAndroid Build Coastguard Worker            return
178*288bf522SAndroid Build Coastguard Worker
179*288bf522SAndroid Build Coastguard Worker        maxtries = 0
180*288bf522SAndroid Build Coastguard Worker        slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
181*288bf522SAndroid Build Coastguard Worker        for slot in slots:
182*288bf522SAndroid Build Coastguard Worker            self.fastboot.set_active(slot)
183*288bf522SAndroid Build Coastguard Worker            self.assertEqual(slot, self.fastboot.getvar("current-slot"))
184*288bf522SAndroid Build Coastguard Worker            self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
185*288bf522SAndroid Build Coastguard Worker            self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
186*288bf522SAndroid Build Coastguard Worker            retry = self.get_exists_integer("slot-retry-count:"+slot)
187*288bf522SAndroid Build Coastguard Worker            if maxtries == 0:
188*288bf522SAndroid Build Coastguard Worker                maxtries = retry
189*288bf522SAndroid Build Coastguard Worker            else:
190*288bf522SAndroid Build Coastguard Worker                self.assertEqual(maxtries, retry)
191*288bf522SAndroid Build Coastguard Worker            self.fastboot.reboot(True)
192*288bf522SAndroid Build Coastguard Worker            self.assertEqual(slot, self.fastboot.getvar("current-slot"))
193*288bf522SAndroid Build Coastguard Worker            self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
194*288bf522SAndroid Build Coastguard Worker            self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
195*288bf522SAndroid Build Coastguard Worker            retry = self.get_exists_integer("slot-retry-count:"+slot)
196*288bf522SAndroid Build Coastguard Worker            if maxtries == 0:
197*288bf522SAndroid Build Coastguard Worker                maxtries = retry
198*288bf522SAndroid Build Coastguard Worker            else:
199*288bf522SAndroid Build Coastguard Worker                self.assertEqual(maxtries, retry)
200*288bf522SAndroid Build Coastguard Worker
201*288bf522SAndroid Build Coastguard Worker    def test_hasslot(self):
202*288bf522SAndroid Build Coastguard Worker        """Tests that A/B devices report partitions that have slots."""
203*288bf522SAndroid Build Coastguard Worker        # Test invalid if not an A/B device
204*288bf522SAndroid Build Coastguard Worker        if not self.get_slotcount():
205*288bf522SAndroid Build Coastguard Worker            return
206*288bf522SAndroid Build Coastguard Worker
207*288bf522SAndroid Build Coastguard Worker        self.assertEqual("yes", self.fastboot.getvar("has-slot:system"))
208*288bf522SAndroid Build Coastguard Worker        self.assertEqual("yes", self.fastboot.getvar("has-slot:boot"))
209*288bf522SAndroid Build Coastguard Worker
210*288bf522SAndroid Build Coastguard Worker        # Additional partition on AndroidThings (IoT) devices
211*288bf522SAndroid Build Coastguard Worker        if device_type == "iot":
212*288bf522SAndroid Build Coastguard Worker            self.assertEqual("yes", self.fastboot.getvar("has-slot:oem"))
213*288bf522SAndroid Build Coastguard Worker
214*288bf522SAndroid Build Coastguard Workerif __name__ == '__main__':
215*288bf522SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
216*288bf522SAndroid Build Coastguard Worker    parser.add_argument("--device-type", default="phone",
217*288bf522SAndroid Build Coastguard Worker                        help="Type of device ('phone' or 'iot').")
218*288bf522SAndroid Build Coastguard Worker    parser.add_argument("extra_args", nargs="*")
219*288bf522SAndroid Build Coastguard Worker    args = parser.parse_args()
220*288bf522SAndroid Build Coastguard Worker
221*288bf522SAndroid Build Coastguard Worker    if args.device_type.lower() not in ("phone", "iot"):
222*288bf522SAndroid Build Coastguard Worker        raise ValueError("Unsupported device type '%s'." % args.device_type)
223*288bf522SAndroid Build Coastguard Worker    device_type = args.device_type.lower()
224*288bf522SAndroid Build Coastguard Worker
225*288bf522SAndroid Build Coastguard Worker    sys.argv[1:] = args.extra_args
226*288bf522SAndroid Build Coastguard Worker    unittest.main(verbosity=3)
227