1#!/usr/bin/env python
2#
3# Copyright (C) 2018 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""VTS test to verify userspace fastboot implementation."""
18
19import os
20import subprocess
21
22from vts.runners.host import asserts
23from vts.runners.host import base_test
24from vts.runners.host import test_runner
25from vts.utils.python.android import api
26
27FASTBOOT_VAR_SUPER_PARTITION_NAME = "super-partition-name"
28
29class VtsFastbootVerificationTest(base_test.BaseTestClass):
30    """Verifies userspace fastboot implementation."""
31
32    def setUpClass(self):
33        """Initializes the DUT and places devices into fastboot mode.
34
35        Attributes:
36            gtest_bin_path: Path to the fuzzy_fastboot gtest binary
37        """
38        self.dut = self.android_devices[0]
39        # precondition_api_level only skips test cases, issuing the
40        # 'adb reboot fastboot' could cause undefined behavior in a
41        # pre-Q device and hence we need to skip the setup for those
42        # devices.
43        if self.dut.getLaunchApiLevel() <= api.PLATFORM_API_LEVEL_P:
44          return
45        self.shell = self.dut.shell
46        self.gtest_bin_path = os.path.join("host", "nativetest64", "fuzzy_fastboot",
47                                           "fuzzy_fastboot")
48        self.dut.cleanUp()
49        self.dut.adb.reboot_fastboot()
50        # The below command blocks until the device enters fastbootd mode to
51        # ensure that the device is in fastbootd mode when setUpClass exits.
52        # If this is not done, VTS self-diagnosis tries to recover the
53        # device as part of test case setup(currently the check returns
54        # immediately without a timeout).
55        self.dut.fastboot.getvar("is-userspace")
56
57    def testFastbootdSlotOperations(self):
58        """Runs fuzzy_fastboot gtest to verify slot operations in fastbootd implementation."""
59        # Test slot operations and getvar partition-type
60        fastboot_gtest_cmd_slot_operations = [
61            "%s" % self.gtest_bin_path, "--serial=%s" % self.dut.serial,
62            "--gtest_filter=Conformance.Slots:Conformance.SetActive"
63        ]
64        # TODO(b/117181762): Add a serial number argument to fuzzy_fastboot.
65        retcode = subprocess.call(fastboot_gtest_cmd_slot_operations)
66        asserts.assertTrue(retcode == 0, "Incorrect slot operations")
67
68    def testLogicalPartitionCommands(self):
69        """Runs fuzzy_fastboot to verify getvar commands related to logical partitions."""
70        fastboot_gtest_cmd_logical_partition_compliance = [
71            "%s" % self.gtest_bin_path, "--serial=%s" % self.dut.serial,
72            "--gtest_filter=LogicalPartitionCompliance.GetVarIsLogical:LogicalPartitionCompliance.SuperPartition"
73        ]
74        retcode = subprocess.call(fastboot_gtest_cmd_logical_partition_compliance)
75        asserts.assertTrue(retcode == 0, "Error in logical partition operations")
76
77    def testSuperPartitionName(self):
78        """Devices launching with DAP must have a super partition named 'super'"""
79        out = self.dut.fastboot.getvar("super-partition-name").strip()
80        asserts.assertTrue("%s: super" % FASTBOOT_VAR_SUPER_PARTITION_NAME in out,
81                           "Devices launching with DAP must have a 'super' partition")
82
83    def testFastbootReboot(self):
84        """Runs fuzzy_fastboot to verify the commands to reboot into fastbootd and bootloader."""
85        fastboot_gtest_cmd_reboot_test = [
86            "%s" % self.gtest_bin_path, "--serial=%s" % self.dut.serial,
87            "--gtest_filter=LogicalPartitionCompliance.FastbootRebootTest"
88        ]
89        retcode = subprocess.call(fastboot_gtest_cmd_reboot_test)
90        asserts.assertTrue(retcode == 0, "Error in fastbootd reboot test")
91
92    def testLogicalPartitionFlashing(self):
93        """Runs fuzzy_fastboot to verify the commands to reboot into fastbootd and bootloader."""
94        fastboot_gtest_cmd_lp_flashing = [
95            "%s" % self.gtest_bin_path, "--serial=%s" % self.dut.serial,
96            "--gtest_filter=LogicalPartitionCompliance.CreateResizeDeleteLP"
97        ]
98        retcode = subprocess.call(fastboot_gtest_cmd_lp_flashing)
99        asserts.assertTrue(retcode == 0, "Error in flashing logical partitions")
100
101    def testCpuAbiInfo(self):
102        """Devices launching with DAP must export cpu-abi."""
103        first_line = self.dut.fastboot.getvar("cpu-abi").splitlines()[0]
104        # Extracts the ABI from the first line, which is something like: 'cpu-abi: arm64-v8a'.
105        cpu_abi = first_line[len("cpu-abi: "):].strip()
106        asserts.assertTrue(cpu_abi in ['armeabi-v7a', 'arm64-v8a',
107                                       'mips', 'mips64',
108                                       'x86', 'x86_64'],
109                           "Unknown CPU ABI '%s' found in fastbootd" % cpu_abi)
110
111    def tearDownClass(self):
112        """Reboot to Android."""
113        if self.dut.isBootloaderMode:
114            self.dut.reboot()
115            self.dut.waitForBootCompletion()
116
117if __name__ == "__main__":
118    test_runner.main()
119