Home | History | Annotate | Download | only in releasetools
      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