• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""
18Utils for running unittests.
19"""
20
21import logging
22import os
23import os.path
24import struct
25import sys
26import unittest
27
28import common
29
30# Some test runner doesn't like outputs from stderr.
31logging.basicConfig(stream=sys.stdout)
32
33
34def 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
41def 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
57def 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
121class ReleaseToolsTestCase(unittest.TestCase):
122  """A common base class for all the releasetools unittests."""
123
124  def tearDown(self):
125    common.Cleanup()
126