Commit Graph

83 Commits

Author SHA1 Message Date
Ivan Lozano b021b2aeb3 Update language to comply with Android’s inclusive language guidance
See https://source.android.com/setup/contribute/respectful-code for reference

 #inclusivefixit

Bug: 161896447
Test: N/A
Change-Id: I9fd970726d739da658f6419a1ccd3e4952b17c78
2020-07-28 15:43:15 -04:00
Yifan Hong 65afc07f9d Support forcefully generating non-AB packages.
Force generate a non-A/B update package when requested.

Bug: 154344887
Test: ota_from_target_files.py --force_non_ab ...
Test: apply it as well

Change-Id: I5e81eb161722e07ef50081b6a16685cbc9963ae2
(cherry picked from commit 7169f754cc)
Merged-In: I5e81eb161722e07ef50081b6a16685cbc9963ae2
2020-05-19 15:23:27 -07:00
Tianjie Xu 41976c725c Factor out the image classes to break circular dependency
This helps to break the circular dependency between common and
blockimgdiff.

Bug: 32379627
Test: unit tests pass
Change-Id: I90b5ff34782acbfac86f36265bd96c207d898bf6
2019-07-15 17:02:23 -07:00
Tao Bao b813120af1 releasetools: Make blockimgdiff Python 3 compatible.
Bug: 131631303
Test: `python -m unittest test_blockimgdiff`
Test: `python3 -m unittest test_blockimgdiff`
Change-Id: I8cf072ca4af6a525bc675cba0be998ff7be7f4f1
2019-06-20 14:30:30 -07:00
Yifan Hong 55988c4677 FileImage: make thread-safe
FileImage needs to be thread-safe because multiple
threads gets data from it when an incremental OTA
package is created.

Test: apply incremental OTA on cuttlefish
Bug: 113175337
Change-Id: I31637fce0fbd66f3fa6c5c478da09bae65a52229
2019-04-12 15:38:48 -07:00
Yifan Hong 8a66a71b06 Allow generating OTA package from non-sparse images.
Test: build OTA package in cuttlefish

Bug: 120041578
Change-Id: I246c38e08376c837b7f126aa19cb8c1d73ed1e26
2019-04-11 14:38:21 -07:00
Yifan Hong 6f3eaeb84d Fix DataImage.ReadRangeSet()
It returns a list of one generator object, not a list
of strings.

Test: test_blockimgdiff
Change-Id: I8962c539c2ce3fae90d428b38c4b0e52c5a2cdad
2019-04-09 17:01:53 -07:00
Yifan Hong bb2658d5e2 releasetools: Really allow removing partitions
- Add hashtree_info to EmptyImage so that BlockDifference.Compute()
can accept EmptyImage() as target image, which is the case when
a partition is removed.

- BlockDifference also checks source_info_dict to determine
whether a partition is dynamic. When a partition is removed,
its name does not appear in target_info_dict.

- Add tests to ensure DynamicPartitionDifference() still works.

Test: DynamicPartitionDifferenceTest
Test: test_blockimgdiff

Change-Id: Iadb1db075f5dc344db6d5ade358c83b01231e443
2019-01-28 11:10:48 -08:00
xunchang b6105dcba3 blockimgdiff: selectively convert 'diff' commands to 'new' to reduce stash size
We cannot simultaneously stash more blocks than the size limit imposed by
the cache size. As a result, some 'diff' commands will be inevitably
converted to new. We used to do this conversion blindly when iterating
through the transfer list. This leads to an unintended large package.

In order to choose the right transfers to convert, we calculate the size
of the compressed data, and build a heuristic about the package size
increase to remove each stash blocks. After the process, the given
package size for the watch device further reduces from 186M->155M.

In some rare cases, the removed stashed blocks don't directly contribute
to the maximum simultaneously stashed size. For example,
stash A: 10 blocks
stash B: 5 blocks
free B: 5 blocks  <-- stash B has been freed before we reach max stashed blocks
stash C: 10 blocks

Converting these blocks lead to an uncertain result. On one hand, patches
are generally smaller than the new data; while on the other hand, the
regenerated graph may have fewer order violation and thus give some size
reduction. But these cases are rare and it seems an overkill to consider all
possible scenarios here.

Bug: 120561199
Test: build non-A/B incrementals and check the size
(p.s. it can be tested on all target files with customed cache threshold)
Change-Id: I599420a91b80f1a1d83d22ee1b336b699050cfb4
2019-01-16 12:59:13 -08:00
xunchang 3df4d5eb6d blockimgdiff: add a function to select and convert 'diff' to new
Package size will be unintended large if we stash more blocks than the
stash limit specified by the cache size. To reduce the maximum size of
simultaneous stashed blocks, we will inevitably convert some 'diff'
commands to 'new' commands.

To mitigate the impact, we add a new function to smartly select the
transfers to convert based on their patch size and compressed size.
This cl converts the transfers that have a larger patch size than the
compressed target sizes. And there's a slightly improvement in the
final package size: from 194M -> 185M.

Bug: 120561199
Test: build a non-A/B incremental package, run simulator
Change-Id: Id73ff736ba4e6901d245ad5549d42310d0740284
2018-12-19 20:21:25 -08:00
xunchang 2153183acf blockimgdiff: Factor out the diff_worker
We will call it at an earlier time to compute the patch size; and
choose the transfers to convert to 'new'.

Bug: 120561199
Test: Generate an incremental update on shiner
Change-Id: I29a0c8e75c9e5b66a266c1387186692a86fcbe43
2018-12-12 17:02:39 -08:00
Tao Bao 32fcdab512 releasetools: Switch to Python logging.
Converts the following files to Python logging.

add_img_to_target_files.py
blockimgdiff.py
build_image.py
check_ota_package_signature.py
common.py
img_from_target_files.py
make_recovery_patch.py
ota_from_target_files.py
sparse_img.py
verity_utils.py

This separates logging outputs from normal outputs, and allows easier
switching between different verbosity levels. It also supports adjusting
logging config via environment variable (LOGGING_CONFIG).

Test: `m dist`
Test: `python -m unittest discover build/make/tools/releasetools`
Change-Id: Idfc3f7aff83e03f41f3c9b5067d64fd595d5192d
2018-10-17 07:51:04 -07:00
Tao Bao 73dd4f45f3 releasetools: Set default stdout and stderr in common.Run().
stdout and stderr will default to subprocess.PIPE and subprocess.STDOUT
respectively (which is the expected behavior from most of the existing
callers), unless caller specifies any of them.

Test: `m dist`
Test: python -m unittest \
          test_common \
          test_add_img_to_target_files \
          test_ota_from_target_files \
          test_validate_target_files
Change-Id: I43b3f08edfa8a9bcfe54baf9848dc705c048e327
2018-10-04 17:05:09 -07:00
Tianjie Xu 67c7cbb9c8 Generate the compute_hash_tree command
Generate the transfer command "compute_hash_tree" for incremental
updates of the non-A/B devices that enable verified boot 1.0

Other changes include:
i.  factor out verity_utils to use both in build_image and blockimgdiff
ii. add a new flag 'hashtree_info_generator' in sparse_image to generate
    the hashtree information.

Bug: 25170618
Test: generate a package for aosp_angler; and run simulator
Change-Id: I4d4d7a3e41dc3da810d2cbf8988e85d187c9ab0e
2018-10-03 13:36:35 -07:00
Tao Bao 76def243ec releasetools: Make scripts pylint clean.
Clean up the following scripts.
  blockimgdiff.py
  common.py
  edify_generator.py
  img_from_target_files.py
  ota_from_target_files.py

Seems we don't have a way to force pylint-ing the scripts using
per-directory pylintrc files (and we don't have pylint tool in AOSP
repo), per
https://android.googlesource.com/platform/tools/repohooks/#todo_limitations.

Test: `m dist`
Test: pylint --rcfile=pylintrc <script.py>
Change-Id: Ia6fd1ddc86f4d84c68e500f225d4a89d0fea8ec7
2018-07-19 10:39:05 -07:00
Tao Bao 5bab0dd1c4 releasetools: Remove RemoveBackwardEdges().
RemoveBackwardEdges() was used only in BBOTA v1 (which has been
deprecated since O). v2+ calls ReverseBackwardEdges() and
ImproveVertexSequence().

Also remove the imgdiff tag of 'trimmed' that would be set through this
function() only.

Test: python -m unittest test_blockimgdiff
Test: Build an incremental non-A/B OTA.
Test: Code search shows no active user.
Change-Id: I3b58ae048a1fbc283269e70fdfa29eb8d184ede7
2018-07-10 22:13:40 -07:00
Tao Bao e709b094e4 releasetools: Allow generating BBOTA for images with shared blocks.
When target defines 'BOARD_EXT4_SHARE_DUP_BLOCKS := true', the generated
system/vendor images may contain shared blocks (i.e. some blocks will
show up in multiple files' block list), which violates the current
assumptions in BBOTA script.

This CL allows generating BBOTAs by considering the first occurrence as
the "owner" of the shared blocks. All the later users of the shared
blocks will have an incomplete block list, whose RangeSet's will be
tagged with 'uses_shared_blocks'.

Files with 'uses_shared_blocks' tag will not be diff'd with imgdiff,
potentially with patch size penalty. Such files will be accounted for in
imgdiff stats report, where we can revisit for a better solution.

Bug: 64109868
Test: Generate BBOTA full and incremental package with targets defining
      'BOARD_EXT4_SHARE_DUP_BLOCKS := true'.
Change-Id: I87fbc22eef7fafe2a470a03fdcfa1babf088ea8d
2018-02-13 11:14:23 -08:00
Tao Bao 4ccea8549e releasetools: Remove the unconditional fallback to bsdiff.
This CL uses the 'incomplete' tag to skip applying imgdiff to files with
incomplete block list. It's not the ideal fix to address the holes in
ext4 images, but would unhide other imgdiff issues covered by the
unconditional fallback.

Bug: 68016761
Test: Generate an incremental OTA package from images with incomplete
      block list. Check the imgdiff stats report.
Test: `python -m unittest test_blockimgdiff`
Change-Id: Ice77686414e70f5e42de35c1757fb31cf02e4fd4
2018-02-13 11:06:20 -08:00
Tao Bao 508b087943 releasetools: Make blockimgdiff.py pylint-clean.
************* Module blockimgdiff
C:433, 0: Unnecessary parens after 'if' keyword (superfluous-parens)
C:687, 0: Wrong hanging indentation (add 4 spaces).
            max_stashed_blocks, self._max_stashed_size, max_allowed,
            ^   | (bad-continuation)
C:688, 0: Wrong hanging indentation (add 4 spaces).
            self._max_stashed_size * 100.0 / max_allowed))
            ^   | (bad-continuation)
C:691, 0: Wrong hanging indentation (remove 2 spaces).
            max_stashed_blocks, self._max_stashed_size))
          | ^ (bad-continuation)
C:898, 0: Wrong hanging indentation (add 4 spaces).
                  "imgdiff" if imgdiff else "bsdiff",
                  ^   | (bad-continuation)
C:899, 0: Wrong hanging indentation (add 4 spaces).
                  xf.tgt_name if xf.tgt_name == xf.src_name else
                  ^   | (bad-continuation)
C:901, 0: Wrong hanging indentation (add 4 spaces).
                  xf.tgt_ranges, xf.src_ranges, e.message))
                  ^   | (bad-continuation)
C:909, 0: Wrong hanging indentation (add 4 spaces).
                      xf.tgt_name,))
                      ^   | (bad-continuation)
C:917, 0: Wrong hanging indentation (add 4 spaces).
                      xf.tgt_name, e.message))
                      ^   | (bad-continuation)
C:961, 0: Wrong hanging indentation (remove 2 spaces).
                xf.patch_len, tgt_size, xf.patch_len * 100.0 / tgt_size,
              | ^ (bad-continuation)
C:962, 0: Wrong hanging indentation (remove 2 spaces).
                xf.style,
              | ^ (bad-continuation)
C:963, 0: Wrong hanging indentation (remove 2 spaces).
                xf.tgt_name if xf.tgt_name == xf.src_name else (
              | ^ (bad-continuation)
C:965, 0: Wrong hanging indentation (remove 2 spaces).
                xf.tgt_ranges, xf.src_ranges))
              | ^ (bad-continuation)
C:1422, 0: Wrong continued indentation (add 28 spaces).
                tgt_skipped.size() * 100.0 / tgt_size, tgt_name))
                ^                           | (bad-continuation)
C:1560, 0: Wrong continued indentation (add 8 spaces).
            split_src_ranges) in enumerate(split_info_list):
            ^       | (bad-continuation)
R:566, 6: Redefinition of src_str type from list to str (redefined-variable-type)
C:1198,25: More than one statement on a single line (multiple-statements)
C:1211,25: More than one statement on a single line (multiple-statements)
C:1220,16: More than one statement on a single line (multiple-statements)
C:1277,38: More than one statement on a single line (multiple-statements)
C:1284,19: More than one statement on a single line (multiple-statements)
C: 19, 0: standard import "import copy" comes before "import common" (wrong-import-order)
C: 20, 0: standard import "import functools" comes before "import common" (wrong-import-order)
C: 21, 0: standard import "import heapq" comes before "import common" (wrong-import-order)
C: 22, 0: standard import "import itertools" comes before "import common" (wrong-import-order)
C: 23, 0: standard import "import multiprocessing" comes before "import common" (wrong-import-order)
C: 24, 0: standard import "import os" comes before "import common" (wrong-import-order)
C: 25, 0: standard import "import os.path" comes before "import common" (wrong-import-order)
C: 26, 0: standard import "import re" comes before "import common" (wrong-import-order)
C: 27, 0: standard import "import subprocess" comes before "import common" (wrong-import-order)
C: 28, 0: standard import "import sys" comes before "import common" (wrong-import-order)
C: 29, 0: standard import "import threading" comes before "import common" (wrong-import-order)
C: 31, 0: standard import "from collections import deque, OrderedDict" comes before "import common" (wrong-import-order)
C: 32, 0: standard import "from hashlib import sha1" comes before "import common" (wrong-import-order)

Test: `pylint --rcfile=pylintrc blockimgdiff.py`
Test: Generate an incremental BBOTA package.
Change-Id: Ia7ecd0e1fa48daf4e43251bdcdfcd08fb316015d
2018-02-12 13:01:34 -08:00
Tao Bao 9739514769 releasetools: Remove the global diff_done in blockimgdiff.py.
pylint complains about undefined `diff_done`:

W:754, 8: Global variable 'diff_done' undefined at the module level (global-variable-undefined)
W:820,14: Global variable 'diff_done' undefined at the module level (global-variable-undefined)

It would still warn about using global statement after adding the
definition.

W:859, 8: Using the global statement (global-statement)
W:925,14: Using the global statement (global-statement)

This CL computes 'diff_done' via 'len(diff_queue)' instead. It also
moves the progress reporting _before_ the diff work. This way it avoids
showing 100% progress with still changing filenames (because multiple
workers could see an empty queue simultaneously upon finishing their own
works).

There're possible alternatives, such as using the 'nonlocal' keyword in
Python 3 (which we're not there yet), or by using mutable object instead
(e.g. 'diff_done = [0]'). This CL looks cleaner, since it just kills the
var.

Test: Generate a BBOTA incremental. Check the on-screen progress
      report.
Test: `pylint --rcfile=pylintrc blockimgdiff.py` no longer complains
      about the global diff_done.
Change-Id: I339824735527e1f794b5b1dc99ff3fdb2da85744
2018-02-12 12:55:25 -08:00
Tao Bao 294651d7b4 releasetools: Add an ImgdiffStats class that reports imgdiff stats.
We have a couple of active imgdiff workarounds (and likely with one more
inbounding that allows having shared blocks in ext4 image). Most of
these workarounds need extending imgdiff's capability. While us not
getting there anytime soon, collect the stats to better understand the
impact of each kind so we can prioritize accordingly.

A sample report is as follows.

  Imgdiff Stats Report
========================

 APK files diff'd with imgdiff (count: 88)
-------------------------------------------

  /system/priv-app/Shell/Shell.apk
  ...

 Large APK files split and diff'd with imgdiff (count: 4)
----------------------------------------------------------

  /system/priv-app/Settings/Settings.apk
  ...

Bug: 68016761
Test: Generate an incremental BBOTA package. Check the stats report.
Test: python -m unittest test_blockimgdiff
Change-Id: I27ad862cde472ab2806db877632ce5a0607420f2
2018-02-09 23:02:32 -08:00
Tao Bao cb73aed1f0 releasetools: Refactor the condition checking for using imgdiff.
In Transfer class, unbundle 'intact' with the monotonicity of the input
ranges. Negate the logic of 'intact', and thus rename it to 'trimmed'.
Move this property from an attribute of Transfer class as the one in
RangeSet.extra. 'trimmed' indicates whether the source / target ranges
have been modified after creating the Transfer() instance.

The logic that determines whether we can apply imgdiff has been
refactored and consolidated into BlockImageDiff.CanUseImgdiff(). Now
both of the two paths call this single copy, i.e. the one that detects
large APKs (before creating Transfer()'s), and the other that's about to
generate the patch for a given Transfer instance.

Bug: 68016761
Test: python -m unittest test_blockimgdiff
Test: Generate an incremental BBOTA package.
Change-Id: Id07195f63f1fa6c3af6e9091940d251cf09fa104
2018-02-09 12:46:01 -08:00
Tao Bao fe97dbd4ce releasetools: RangeSet.monotonic is not an optional attribute.
'monotonic' has been non-optional since [1] (L-MR1). Fix the comment in
RangeSet.parse(), as well as the use in blockimgdiff.py.

[1] commit 8b72aefb5a.

Test: Generate an incremental BBOTA package.
Change-Id: I7f95231683473b4f0f07f9c83fccc0e36a1340cb
2018-02-06 16:00:52 -08:00
Tianjie Xu df1166e92f Protect SparseImage._GetRangeData() with lock
The generator function is not thread safe and is prone to race
conditions. This CL uses a lock to protect this generator and loose the
locks elsewhere, e.g. 'WriteRangeDataToFd()'.

Bug: 71908713
Test: Generate an incremental package several times for angler 4208095 to 4442250.
Change-Id: I9e6f0a182a1ba7904a597f403f2b12fe05016513
2018-01-29 11:52:10 -08:00
Tianjie Xu 8a7ed9f771 Double check the sha1 for ranges during package generation
Check that the Sha1 for src&tgt ranges are correct before computing
patches. This adds ~6 seconds overhead for ~2400 commands.

Bug: 71908713
Test: Generate an incremental package from angler 4208095 to 4442250.
Change-Id: I8cf8ce132fb09a22f7d6689274ddb4a27770be76
2018-01-28 01:54:52 +00:00
Tianjie Xu 20a86cdd8d Iterate through the sorted file map when finding transfers
This helps to generate a deterministic package.

Bug: 71770360
Test: Generate a incremental package and transfers are added by file name.
Change-Id: I7562a200b97a1babbb09a77801324cc9408cc01f
2018-01-12 12:21:00 -08:00
Tianjie Xu d3bf67e1d3 Sort the split transfers to generate a determinate package
We split large apks and generated patches for them in parallel,
resulting in nondeterminate packages between different runs. This CL
sort the split transfers by target name first; and then add them
sequentially to the final transfer list.

Also fix a side effect where we may generate a wrong sha1 for split
ranges due to synchronization error.

Bug: 71770360
Bug: 71759418

Test: Generate the package several times, compare the log and the transfer list.
Change-Id: I2a49e22594d59ffaa98b11edc776be4e3c4c561f
2018-01-10 12:23:57 -08:00
Tao Bao 186ec99eb9 releasetools: Fix a bug in blockimgdiff.HeapItem.
HeapItem defines __bool__(), which contains a logical error that should
return the opposite value.

Note that the bug only manifests while using Python 3, which calls
__bool__(). With Python 2, `if x:` or bool(x) actually calls
x.__nonzero__() or x.__len__(). If a class defines neither __len__() nor
__nonzero__(), as the case in HeapItem, it always returns True.

Test: python -m unittest test_blockimgdiff
Test: python3 -m unittest test_blockimgdiff
Test: Generate an incremental non-A/B OTA package successfully.
Change-Id: Ibe8430e0b495a7d2f430cfffb716d2536ffb53d2
2018-01-02 09:54:32 -08:00
Tianjie Xu 41390d4e1e Improve the comment in AddSplitTransfers
Bug: 69624507
Test: build an incremental package
Change-Id: I54dac0a2ddcc19b722e352fb19d53ff20444fa42
2017-11-22 11:35:18 -08:00
Tianjie Xu f68b50f963 Fall back to normal split if imgdiff fails when splitting large apks
Imgdiff expects the input files to be valid zip archives. During the
split of large apks, imgdiff may fail when there's a hole in the input
file; potentially due to the blocks allocation of mke2fs. This CL solves
the issue by falling back to normal split in case of the imgdiff split
failure. The split transfers will then use bsdiff instead.

Bug: 69624507
Test: generate the incremental package for the failed targets and check the
transfers.
Change-Id: I4882452378123e60ad3434053b57f33e53ac4b82
2017-11-21 23:37:36 -08:00
Tianjie Xu 2536607d90 Add multithread support to call imgdiff with block-limit
With the new implementation of handling large apks, we need to call
imgdiff with block-limit to split the apk and generate the patch at
the same time. The call to imgdiff would significantly increase the
time consumption of the "FindTransfers" function which we used to
execute sequentially. This cl addresses this issue and speeds up the
process by making the imgdiff call parallel.

Bug: 34220646
Test: Create and sideload an incremental package for angler
Change-Id: Id62e348418fc1d22e32ea6c8ac16d9ab3ec92d7b
2017-11-13 14:58:05 -08:00
Tao Bao d41c9179d2 releasetools: Fix the wrong command when falling back to bsdiff.
Commit b937ead5d9 added the fallback to
bsdiff on imgdiff failures. However, it missed setting the transfer
style accordingly, which led to patch header mismatch.

Bug: 68659848
Test: Generate an incremental that has the fallback from imgdiff to
      bsdiff. Examine the generated transfer list and verify that it has
      "bsdiff" for the fallback command.

Change-Id: I55e46879d590a8af82ea796b9d98ffdb30360408
2017-10-31 12:09:07 -07:00
Tao Bao b937ead5d9 releasetools: Work around the issue with mke2fs created images.
When generating block based OTAs, we read files from the sparse image
directly with the help of block map file. However, the block map info
might not be accurate if the image is created with mke2fs. Because
mke2fs may skip allocating actual blocks if they contain all zeros.
ota_from_target_files.py consequently passes incomplete APK files to
imgdiff, which fails to generate patches.

This CL works around the issue by falling back from imgdiff to bsdiff on
failures. We should figure out a better way in b/68016761 to remove the
workaround, which would otherwise hide other issues in imgdiff.

Bug: 67824829
Bug: 68016761
Test: ota_from_target_files.py passes on previously failing TF zips.
Change-Id: Ib24c5b5f89812b97a0c87c6bf0dc147ae39bc92f
2017-10-19 16:56:22 -07:00
Tao Bao 39451582c4 releasetools: Add a verbose parameter to common.Run().
Caller can optionally specify the verbose flag which overrides
OPTIONS.verbose. The command line won't be outputed with verbose=False.
This is useful for cases that a) those command lines are less useful
(but will spam the output otherwise); b) sensitive info is part of the
invocation.

'verbose=False' will be consumed by common.Run() only, instead of being
passed to subprocess.Popen().

Test: ota_from_target_files.py on a block based OTA.
Change-Id: I7d5b4094d756a60f84f89c6a965e7ccc68e435f8
2017-05-04 11:18:56 -07:00
Tianjie Xu b59c17fc8f Provide more info for bsdiff/imgdiff exceptions.
When bsdiff/imgdiff fails, dump the output along with the src/tgt
filenames and block ranges. Also, exit the script gracefully instead
of raising an exception about iterating over 'NoneType'.

Bug: 31381530
Test: Package generates successfully for angler, and error outputs
      correctly with error injection.

Change-Id: I06a2dfe545fbdff7043de05fee34b378453a9291
2017-03-14 18:51:21 -07:00
Tao Bao 33635b1f32 releasetools: Fix the diff_worker progress report.
Test: Observe the progress update during an incremental generation.
Change-Id: Ib0629a0fd9f925076fd20a040345c4f169133c30
2017-03-12 13:02:51 -07:00
Tao Bao 8fad03e771 releasetools: Drop the support for BBOTA v1 and v2.
BBOTA v1 and v2 (introduced in L and L MR1 respectively) don't support
resumable OTA. We shouldn't generate packages using v1/v2 at the risk of
bricking devices.

BBOTA v3 (since M) and v4 (since N) both support resumable OTAs. BBOTA
v4 additionally supports using FEC to possibly recover a corrupted
image.

Bug: 33694730
Test: Generate full and incremental OTAs w/ and w/o the CL. They should
      give identical packages (in v4).
Change-Id: Ib89d9cd63ba08e8e9aa4131bed18876b89d244c0
2017-03-09 12:25:46 -08:00
Tao Bao 183e56e83d releasetools: Reduce memory footprint for BBOTA generation.
The major issue with the existing implementation is unnecessarily
holding too much data in memory, such as HashBlocks() which first reads
in *all* the data to a list before hashing. We can leverage generator
functions to stream such operations.

This CL makes the following changes to reduce the peak memory use.
 - Adding RangeSha1() and WriteRangeDataToFd() to Image classes. These
   functions perform the operations on-the-fly.
 - Caching the computed SHA-1 values for a Transfer instance.

As a result, this CL reduces the peak memory use by ~80% (e.g. reducing
from 5.85GB to 1.16GB for the same incremental, as shown by "Maximum
resident set size" from `/usr/bin/time -v`). It also effectively
improves the (package generation) performance by ~30%.

Bug: 35768998
Bug: 32312123
Test: Generating the same incremental w/ and w/o the CL give identical
      output packages.
Change-Id: Ia5c6314b41da73dd6fe1dbe2ca81bbd89b517cec
2017-03-06 08:46:30 -08:00
Tao Bao e8c68a03c8 releasetools: Fix an equality check bug when asserting stash size.
Otherwise the comparison is inconsistent between ReviseStashSize() and
WriteTransfers().

Bug: 35775675
Test: Successfully generate a previously failed incremental.
Change-Id: I554a51a210bf322cb5c79e28cf85607a417b094a
2017-02-26 10:58:22 -08:00
Tao Bao 3c5a16d49c releasetools: Fix a bug in ReviseStashSize().
We check the needed stash size in ReviseStashSize(), and may not
generate a stash command if it would exceed the max allowed size. This
CL fixes a bug when skipping a stash operation: we shouldn't update the
'stashes' map if a stash command won't be generated.

Bug: 35313668
Test: Successfully generate the package that was failing due to the bug.
Change-Id: If0a3a5fadda9b4a4edad66a2a5826b5f978400ae
2017-02-13 12:31:42 -08:00
Tao Bao 3a2e350239 blockimgdiff.py: Clean up stash id computation in BBOTA v3+.
Only BBOTA v2 needs to maintain a pool of available 'stash slot id'.
BBOTA v3+ uses the hash of the stashed blocks as the slot id, which
doesn't need the id pool anymore.

Bug: 33694544
Test: Generate v2 and v4 incrementals w/ and w/o the CL. They produce
      the same packages respectively.
Change-Id: I8121af5b6b1bee98c3639d54a00b06fd12e378e8
2016-12-28 09:26:46 -08:00
Tao Bao 304ee27e88 blockimgdiff.py: Add a test case for ReviseStashSize().
Bug: 33687949
Test: python -m unittest test_blockimgdiff
Change-Id: I31e42648d2c0e60b941908c098ce5ccc967861ca
2016-12-19 11:17:12 -08:00
Tao Bao e27acfdc41 releasetools: Fix the computation in ReviseStashSize().
We compute the max stashed_blocks in ReviseStashSize(), prior to calling
WriteTransfers(), to avoid running out of space due to stashing.

There is a bug when computing the to-be-freed stashed blocks, where we
wrongly free the space _before_ executing the transfer command. This leads
to a script failure where the max stash size violates the max allowed
size in WriteTransfers().

Note that this bug doesn't affect already generated packages. It's only
an underestimate in ReviseStashSize(). The check in WriteTransfers() has
been correct to ensure the max stash size.

Bug: 33687949
Test: Successfully generated incremental OTA which failed previously.
Change-Id: I4f4f043c6f521fce81ca5286e6156f22d99bf7f7
2016-12-16 11:26:05 -08:00
Tao Bao e3554167e2 Merge "releasetools: Make BBOTA incremental generation repeatable."
am: b9bd78d110

Change-Id: I6402481bf300b52d36df1570cceeae6ec3ff4f8f
2016-11-04 21:29:15 +00:00
Tao Bao 3348228423 releasetools: Make BBOTA incremental generation repeatable.
set() doesn't keep elements according to the order of insertion. So
Transfers managed with set() in intermediate steps may not appear in the
same order across runs. This leads to slightly different output packages
when generating the same incremental OTA.

This CL fixes the issue by replacing set() with OrderedDict() in
blockimgdiff.GenerateDigraph() and blockimgdiff.FindVertexSequence().

It also adds a testcase that ensures blockimgdiff.GenerateDigraph()
preserves the insertion order for Transfer.goes_after set.

Bug: 32220816
Test: ota_from_target_files.py gives identical package when running
multiple times.

Change-Id: I56d551e5ca926993ab46896e33c80e0ce42e506a
2016-10-26 09:40:50 -07:00
Tao Bao 7f5f23160d Merge "Analyze unchanged blocks in odex files." am: 6e12b72966 am: 0493339a1f
am: 4fbdde5150

Change-Id: Ibbd1b92b81249b7f11de1ba166ff04ee7ba73b88
2016-09-28 17:18:15 +00:00
Tao Bao 08c8583aea Analyze unchanged blocks in odex files.
In BBOTA, we generate patches based on _all_ the blocks of a pair of
input files (src and tgt). For security incremental OTAs, one common
pattern is that only a few blocks are changed in odex files (e.g.
headers). We don't really need to stash/patch the unchanged blocks.

This CL analyzes the unchanged blocks in odex files and computes the
diff for the changed blocks only. It reduces the OTA install time by
about 25% to 40% in our experiments, by paying an increase of 5% to 30%
OTA generation time cost.

Bug: 31570716
Test: Generate an incremental and apply on device.

Change-Id: If842c1afeff6894a3d27eb60b7e8f65a179b7977
2016-09-23 12:15:23 -07:00
Tianjie Xu 37e29301e6 Avoid writing too much new data per transfer
Limit the number of blocks in each 'new' command to 1024. This should
decrease the chance of fsync error during an OTA update, similiar to
what we have done in b/29535618.

Bug: 29607757
Change-Id: I89f0a845d71eb810766e39860ab667c61b61a417
2016-06-23 18:00:16 -07:00
Tianjie Xu b64439b291 Limit the number of blocks in command zero
Limit the number of blocks in command zero to 1024 blocks. This
prevents the target size of one command from being too large and
might help to avoid fsync errors during the OTA update.

Bug: 29535618
Change-Id: Ic630cea2599138516162bd0029e2e4b2af75bf4f
(cherry picked from commit bb848c54a7)
2016-06-21 23:19:30 +00:00
Tianjie Xu bb848c54a7 Limit the number of blocks in command zero
Limit the number of blocks in command zero to 1024 blocks. This
prevents the target size of one command from being too large and
might help to avoid fsync errors during the OTA update.

Bug: 29535618
Change-Id: Ic630cea2599138516162bd0029e2e4b2af75bf4f
2016-06-21 16:13:06 -07:00