upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
25
android/system/extras/tests/bootloader/Android.mk
Normal file
25
android/system/extras/tests/bootloader/Android.mk
Normal file
|
@ -0,0 +1,25 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Build a module that has all of the python files as its LOCAL_PICKUP_FILES.
|
||||
# Since no action needs to be taken to compile the python source, just
|
||||
# use BUILD_PHONY_PACKAGE to give us a target to execute.
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := bootloader_unit_test
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
bootloader_py_files := $(call find-subdir-files, *.py)
|
||||
|
||||
bootloader_zip_prefix := $(TARGET_OUT_DATA)/py_bootloader
|
||||
bootloader_zip_path := $(bootloader_zip_prefix)/nativetest/py_bootloader
|
||||
|
||||
GEN := $(addprefix $(bootloader_zip_path)/, $(bootloader_py_files))
|
||||
$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
|
||||
$(GEN) : PRIVATE_CUSTOM_TOOL = cp $< $@
|
||||
$(GEN) : $(bootloader_zip_path)/% : $(LOCAL_PATH)/%
|
||||
$(transform-generated-source)
|
||||
|
||||
LOCAL_PICKUP_FILES := $(bootloader_zip_prefix)/nativetest
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(GEN)
|
||||
|
||||
include $(BUILD_PHONY_PACKAGE)
|
61
android/system/extras/tests/bootloader/bootctl.py
Normal file
61
android/system/extras/tests/bootloader/bootctl.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Copyright (C) 2016 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.
|
||||
|
||||
class Bootctl(object):
|
||||
def __init__(self, device):
|
||||
self.device = device
|
||||
self.base = ["bootctl"]
|
||||
|
||||
def _exec(self, cmd):
|
||||
return self.device.shell_nocheck(self.base + [cmd])
|
||||
|
||||
def get_number_slots(self):
|
||||
"""returns number of slots"""
|
||||
|
||||
return int(self._exec("get-number-slots")[1])
|
||||
|
||||
def get_current_slot(self):
|
||||
"""returns current slot number"""
|
||||
|
||||
return int(self._exec("get-current-slot")[1])
|
||||
|
||||
def mark_boot_successful(self):
|
||||
"""returns true on success, false on failure"""
|
||||
|
||||
return self._exec("mark-boot-successful")[0] == 0
|
||||
|
||||
def set_active_boot_slot(self, slot):
|
||||
"""returns true on success, false on failure"""
|
||||
|
||||
return self._exec("set-active-boot-slot " + str(slot))[0] == 0
|
||||
|
||||
def set_slot_as_unbootable_slot(self, slot):
|
||||
"""returns true on success, false on failure"""
|
||||
|
||||
return self._exec("set-slot-as-unbootable " + str(slot))[0] == 0
|
||||
|
||||
def is_slot_bootable(self, slot):
|
||||
"""Returns true if slot is bootable"""
|
||||
|
||||
return self._exec("is-slot-bootable " + str(slot))[0] == 0
|
||||
|
||||
def is_slot_marked_successful(self, slot):
|
||||
"""returns true on success, false on failure"""
|
||||
|
||||
return self._exec("is-slot-marked-successful " + str(slot))[0] == 0
|
||||
|
||||
def get_suffix(self, slot):
|
||||
"""returns suffix string for specified slot number"""
|
||||
|
||||
return self._exec("get-suffix " + str(slot))[1].strip()
|
225
android/system/extras/tests/bootloader/bootloadertest.py
Normal file
225
android/system/extras/tests/bootloader/bootloadertest.py
Normal file
|
@ -0,0 +1,225 @@
|
|||
# Copyright (C) 2016 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.
|
||||
|
||||
import adb
|
||||
import argparse
|
||||
import os
|
||||
import unittest
|
||||
import fastboot
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# Default values for arguments
|
||||
device_type = "phone"
|
||||
|
||||
class ShellTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.fastboot = fastboot.FastbootDevice()
|
||||
|
||||
def exists_validvals(self, varname, varlist, validlist):
|
||||
self.assertIn(varname, varlist)
|
||||
self.assertIn(varlist[varname], validlist)
|
||||
return varlist[varname]
|
||||
|
||||
def exists_yes_no(self, varname, varlist):
|
||||
return self.exists_validvals(varname, varlist, ["yes", "no"])
|
||||
|
||||
def exists_nonempty(self, varname, varlist):
|
||||
self.assertIn(varname, varlist)
|
||||
self.assertGreater(len(varlist[varname]), 0)
|
||||
return varlist[varname]
|
||||
|
||||
def exists_integer(self, varname, varlist, base=10):
|
||||
val = 0
|
||||
self.assertIn(varname, varlist)
|
||||
try:
|
||||
val = int(varlist[varname], base)
|
||||
except ValueError:
|
||||
self.fail("%s (%s) is not an integer" % (varname, varlist[varname]))
|
||||
return val
|
||||
|
||||
def get_exists(self, varname):
|
||||
val = self.fastboot.getvar(varname)
|
||||
self.assertIsNotNone(val)
|
||||
return val
|
||||
|
||||
def get_exists_validvals(self, varname, validlist):
|
||||
val = self.get_exists(varname)
|
||||
self.assertIn(val, validlist)
|
||||
return val
|
||||
|
||||
def get_exists_yes_no(self, varname):
|
||||
return self.get_exists_validvals(varname, ["yes", "no"])
|
||||
|
||||
def get_exists_nonempty(self, varname):
|
||||
val = self.get_exists(varname)
|
||||
self.assertGreater(len(val), 0)
|
||||
return val
|
||||
|
||||
def get_exists_integer(self, varname, base=10):
|
||||
val = self.get_exists(varname)
|
||||
try:
|
||||
num = int(val, base)
|
||||
except ValueError:
|
||||
self.fail("%s (%s) is not an integer" % (varname, val))
|
||||
return num
|
||||
|
||||
def get_slotcount(self):
|
||||
slotcount = 0
|
||||
try:
|
||||
val = self.fastboot.getvar("slot-count")
|
||||
if val != None:
|
||||
slotcount = int(val)
|
||||
except ValueError:
|
||||
self.fail("slot-count (%s) is not an integer" % val)
|
||||
except subprocess.CalledProcessError:
|
||||
print "Does not appear to be an A/B device."
|
||||
if not slotcount:
|
||||
print "Does not appear to be an A/B device."
|
||||
return slotcount
|
||||
|
||||
def test_getvarall(self):
|
||||
"""Tests that required variables are reported by getvar all"""
|
||||
|
||||
var_all = self.fastboot.getvar_all()
|
||||
self.exists_nonempty("version-baseband", var_all)
|
||||
self.exists_nonempty("version-bootloader", var_all)
|
||||
self.exists_nonempty("product", var_all)
|
||||
self.exists_yes_no("secure", var_all)
|
||||
self.exists_yes_no("unlocked", var_all)
|
||||
self.exists_validvals("off-mode-charge", var_all, ["0", "1"])
|
||||
self.assertIn("variant", var_all)
|
||||
voltage = self.exists_nonempty("battery-voltage", var_all)
|
||||
if voltage[-2:].lower() == "mv":
|
||||
voltage = voltage[:-2]
|
||||
try:
|
||||
voltnum = float(voltage)
|
||||
except ValueError:
|
||||
self.fail("battery-voltage (%s) is not a number" % (varname, voltage))
|
||||
self.exists_yes_no("battery-soc-ok", var_all)
|
||||
maxdl = self.exists_integer("max-download-size", var_all, 16)
|
||||
self.assertGreater(maxdl, 0)
|
||||
|
||||
if "slot-count" in var_all:
|
||||
try:
|
||||
slotcount = int(var_all["slot-count"])
|
||||
except ValueError:
|
||||
self.fail("slot-count (%s) is not an integer" % var_all["slot-count"])
|
||||
if slotcount > 1:
|
||||
# test for A/B variables
|
||||
slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
|
||||
self.exists_validvals("current-slot", var_all, slots)
|
||||
|
||||
# test for slot metadata
|
||||
for slot in slots:
|
||||
self.exists_yes_no("slot-unbootable:"+slot, var_all)
|
||||
self.exists_yes_no("slot-unbootable:"+slot, var_all)
|
||||
self.exists_integer("slot-retry-count:"+slot, var_all)
|
||||
else:
|
||||
print "This does not appear to be an A/B device."
|
||||
|
||||
def test_getvar_nonexistent(self):
|
||||
"""Tests behaviour of nonexistent variables."""
|
||||
|
||||
self.assertIsNone(self.fastboot.getvar("fhqwhgads"))
|
||||
|
||||
def test_getvar(self):
|
||||
"""Tests all variables separately"""
|
||||
|
||||
self.get_exists_nonempty("version-baseband")
|
||||
self.get_exists_nonempty("version-bootloader")
|
||||
self.get_exists_nonempty("product")
|
||||
self.get_exists_yes_no("secure")
|
||||
self.get_exists_yes_no("unlocked")
|
||||
self.get_exists_validvals("off-mode-charge", ["0", "1"])
|
||||
self.get_exists("variant")
|
||||
voltage = self.get_exists_nonempty("battery-voltage")
|
||||
if voltage[-2:].lower() == "mv":
|
||||
voltage = voltage[:-2]
|
||||
try:
|
||||
voltnum = float(voltage)
|
||||
except ValueError:
|
||||
self.fail("battery-voltage (%s) is not a number" % voltage)
|
||||
self.get_exists_yes_no("battery-soc-ok")
|
||||
maxdl = self.get_exists_integer("max-download-size", 16)
|
||||
self.assertGreater(maxdl, 0)
|
||||
|
||||
slotcount = self.get_slotcount()
|
||||
if slotcount > 1:
|
||||
# test for A/B variables
|
||||
slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
|
||||
self.get_exists_validvals("current-slot", slots)
|
||||
|
||||
# test for slot metadata
|
||||
for slot in slots:
|
||||
self.get_exists_yes_no("slot-unbootable:"+slot)
|
||||
self.get_exists_yes_no("slot-successful:"+slot)
|
||||
self.get_exists_integer("slot-retry-count:"+slot)
|
||||
|
||||
def test_setactive(self):
|
||||
"""Tests that A/B devices can switch to each slot, and the change persists over a reboot."""
|
||||
# Test invalid if not an A/B device
|
||||
slotcount = self.get_slotcount()
|
||||
if not slotcount:
|
||||
return
|
||||
|
||||
maxtries = 0
|
||||
slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
|
||||
for slot in slots:
|
||||
self.fastboot.set_active(slot)
|
||||
self.assertEqual(slot, self.fastboot.getvar("current-slot"))
|
||||
self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
|
||||
self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
|
||||
retry = self.get_exists_integer("slot-retry-count:"+slot)
|
||||
if maxtries == 0:
|
||||
maxtries = retry
|
||||
else:
|
||||
self.assertEqual(maxtries, retry)
|
||||
self.fastboot.reboot(True)
|
||||
self.assertEqual(slot, self.fastboot.getvar("current-slot"))
|
||||
self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
|
||||
self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
|
||||
retry = self.get_exists_integer("slot-retry-count:"+slot)
|
||||
if maxtries == 0:
|
||||
maxtries = retry
|
||||
else:
|
||||
self.assertEqual(maxtries, retry)
|
||||
|
||||
def test_hasslot(self):
|
||||
"""Tests that A/B devices report partitions that have slots."""
|
||||
# Test invalid if not an A/B device
|
||||
if not self.get_slotcount():
|
||||
return
|
||||
|
||||
self.assertEqual("yes", self.fastboot.getvar("has-slot:system"))
|
||||
self.assertEqual("yes", self.fastboot.getvar("has-slot:boot"))
|
||||
|
||||
# Additional partition on AndroidThings (IoT) devices
|
||||
if device_type == "iot":
|
||||
self.assertEqual("yes", self.fastboot.getvar("has-slot:oem"))
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--device-type", default="phone",
|
||||
help="Type of device ('phone' or 'iot').")
|
||||
parser.add_argument("extra_args", nargs="*")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.device_type.lower() not in ("phone", "iot"):
|
||||
raise ValueError("Unsupported device type '%s'." % args.device_type)
|
||||
device_type = args.device_type.lower()
|
||||
|
||||
sys.argv[1:] = args.extra_args
|
||||
unittest.main(verbosity=3)
|
116
android/system/extras/tests/bootloader/haltest.py
Normal file
116
android/system/extras/tests/bootloader/haltest.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
# Copyright (C) 2016 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.
|
||||
|
||||
import bootctl
|
||||
import shelltest
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
# Note: In order to run these tests, the device must be able to boot
|
||||
# from all slots on the device.
|
||||
class HalTest(shelltest.ShellTest):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HalTest, self).__init__(*args, **kwargs)
|
||||
self.bootctl = bootctl.Bootctl(self.device)
|
||||
|
||||
def test_slots(self):
|
||||
"""Test that all slots are reported and named uniquely."""
|
||||
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
num_slots = self.bootctl.get_number_slots()
|
||||
suffixes = dict()
|
||||
for slot in range(num_slots):
|
||||
suffix = self.bootctl.get_suffix(slot)
|
||||
self.assertNotEqual(suffix, "(null)")
|
||||
suffixes[suffix] = slot
|
||||
self.assertEqual(len(suffixes), num_slots)
|
||||
|
||||
def test_mark_successful(self):
|
||||
"""Ensure mark successful works, and persists on reboot.
|
||||
|
||||
Ensure that mark_successful will mark the slot as
|
||||
successful, and that the HAL sees this. First resets
|
||||
slot-successful by setting the active slot to the current one."""
|
||||
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
slot = self.bootctl.get_current_slot()
|
||||
self.assertTrue(self.bootctl.set_active_boot_slot(slot))
|
||||
self.assertFalse(self.bootctl.is_slot_marked_successful(slot))
|
||||
self.assertTrue(self.bootctl.mark_boot_successful())
|
||||
self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
|
||||
self.device.reboot()
|
||||
self.device.wait()
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
|
||||
|
||||
def test_switch_slots(self):
|
||||
"""Test that setActiveBootSlot works and persists
|
||||
|
||||
Ensure switching slots works, and that setting the slot does not
|
||||
change the reported slot until the reboot."""
|
||||
|
||||
# Cycle through all slots once
|
||||
num_slots = self.bootctl.get_number_slots()
|
||||
for i in range(num_slots):
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
slot = self.bootctl.get_current_slot()
|
||||
new_slot = (slot + 1) % num_slots
|
||||
self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
|
||||
slot2 = self.bootctl.get_current_slot()
|
||||
self.assertEqual(slot, slot2)
|
||||
self.device.reboot()
|
||||
self.device.wait()
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
self.assertEqual(new_slot, self.bootctl.get_current_slot())
|
||||
|
||||
def test_unbootable(self):
|
||||
"""Test setSlotAsUnbootable
|
||||
|
||||
Test that the device will attempt to roll back to a valid slot if
|
||||
the current slot is unbootable."""
|
||||
|
||||
# Cycle through all slots once
|
||||
num_slots = self.bootctl.get_number_slots()
|
||||
for i in range(num_slots):
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
slot = self.bootctl.get_current_slot()
|
||||
new_slot = (slot + 1) % num_slots
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
|
||||
self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
|
||||
self.assertTrue(self.bootctl.set_slot_as_unbootable_slot(new_slot))
|
||||
self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
|
||||
self.device.reboot()
|
||||
self.device.wait()
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
self.assertEqual(slot, self.bootctl.get_current_slot())
|
||||
self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
|
||||
self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
|
||||
self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
|
||||
self.device.reboot()
|
||||
self.device.wait()
|
||||
self.device.root()
|
||||
self.device.wait()
|
||||
self.assertEqual(new_slot, self.bootctl.get_current_slot());
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=3)
|
22
android/system/extras/tests/bootloader/shelltest.py
Normal file
22
android/system/extras/tests/bootloader/shelltest.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Copyright (C) 2016 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.
|
||||
|
||||
import adb
|
||||
import os
|
||||
import unittest
|
||||
|
||||
class ShellTest(unittest.TestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ShellTest, self).__init__(*args, **kwargs)
|
||||
self.device = adb.get_device(os.getenv("BOOTLOADER_TEST_SERIAL"));
|
Loading…
Add table
Add a link
Reference in a new issue