1 # 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 """ 18 Utils for running unittests. 19 """ 20 21 import logging 22 import os 23 import os.path 24 import struct 25 import sys 26 import unittest 27 28 import common 29 30 # Some test runner doesn't like outputs from stderr. 31 logging.basicConfig(stream=sys.stdout) 32 33 34 def get_testdata_dir(): 35 """Returns the testdata dir, in relative to the script dir.""" 36 # The script dir is the one we want, which could be different from pwd. 37 current_dir = os.path.dirname(os.path.realpath(__file__)) 38 return os.path.join(current_dir, 'testdata') 39 40 41 def get_search_path(): 42 """Returns the search path that has 'framework/signapk.jar' under.""" 43 current_dir = os.path.dirname(os.path.realpath(__file__)) 44 for path in ( 45 # In relative to 'build/make/tools/releasetools' in the Android source. 46 ['..'] * 4 + ['out', 'host', 'linux-x86'], 47 # Or running the script unpacked from otatools.zip. 48 ['..']): 49 full_path = os.path.realpath(os.path.join(current_dir, *path)) 50 signapk_path = os.path.realpath( 51 os.path.join(full_path, 'framework', 'signapk.jar')) 52 if os.path.exists(signapk_path): 53 return full_path 54 return None 55 56 57 def construct_sparse_image(chunks): 58 """Returns a sparse image file constructed from the given chunks. 59 60 From system/core/libsparse/sparse_format.h. 61 typedef struct sparse_header { 62 __le32 magic; // 0xed26ff3a 63 __le16 major_version; // (0x1) - reject images with higher major versions 64 __le16 minor_version; // (0x0) - allow images with higer minor versions 65 __le16 file_hdr_sz; // 28 bytes for first revision of the file format 66 __le16 chunk_hdr_sz; // 12 bytes for first revision of the file format 67 __le32 blk_sz; // block size in bytes, must be a multiple of 4 (4096) 68 __le32 total_blks; // total blocks in the non-sparse output image 69 __le32 total_chunks; // total chunks in the sparse input image 70 __le32 image_checksum; // CRC32 checksum of the original data, counting 71 // "don't care" as 0. Standard 802.3 polynomial, 72 // use a Public Domain table implementation 73 } sparse_header_t; 74 75 typedef struct chunk_header { 76 __le16 chunk_type; // 0xCAC1 -> raw; 0xCAC2 -> fill; 77 // 0xCAC3 -> don't care 78 __le16 reserved1; 79 __le32 chunk_sz; // in blocks in output image 80 __le32 total_sz; // in bytes of chunk input file including chunk header 81 // and data 82 } chunk_header_t; 83 84 Args: 85 chunks: A list of chunks to be written. Each entry should be a tuple of 86 (chunk_type, block_number). 87 88 Returns: 89 Filename of the created sparse image. 90 """ 91 SPARSE_HEADER_MAGIC = 0xED26FF3A 92 SPARSE_HEADER_FORMAT = "<I4H4I" 93 CHUNK_HEADER_FORMAT = "<2H2I" 94 95 sparse_image = common.MakeTempFile(prefix='sparse-', suffix='.img') 96 with open(sparse_image, 'wb') as fp: 97 fp.write(struct.pack( 98 SPARSE_HEADER_FORMAT, SPARSE_HEADER_MAGIC, 1, 0, 28, 12, 4096, 99 sum(chunk[1] for chunk in chunks), 100 len(chunks), 0)) 101 102 for chunk in chunks: 103 data_size = 0 104 if chunk[0] == 0xCAC1: 105 data_size = 4096 * chunk[1] 106 elif chunk[0] == 0xCAC2: 107 data_size = 4 108 elif chunk[0] == 0xCAC3: 109 pass 110 else: 111 assert False, "Unsupported chunk type: {}".format(chunk[0]) 112 113 fp.write(struct.pack( 114 CHUNK_HEADER_FORMAT, chunk[0], 0, chunk[1], data_size + 12)) 115 if data_size != 0: 116 fp.write(os.urandom(data_size)) 117 118 return sparse_image 119 120 121 class ReleaseToolsTestCase(unittest.TestCase): 122 """A common base class for all the releasetools unittests.""" 123 124 def tearDown(self): 125 common.Cleanup() 126