releasetools: Always write the last block if it's padded.
In BBOTAs if the last block of a DataImage is padded, we should always write the whole block even for incremental OTAs. Because otherwise the last block may be skipped if unchanged, but would fail the post-install verification if it has non-zero contents in the padding bytes. Bug: 23828506 Change-Id: I4b0af7344d18261258cd48d18c029c089d6ff365
This commit is contained in:
@@ -106,11 +106,13 @@ class DataImage(Image):
|
|||||||
assert not (trim and pad)
|
assert not (trim and pad)
|
||||||
|
|
||||||
partial = len(self.data) % self.blocksize
|
partial = len(self.data) % self.blocksize
|
||||||
|
padded = False
|
||||||
if partial > 0:
|
if partial > 0:
|
||||||
if trim:
|
if trim:
|
||||||
self.data = self.data[:-partial]
|
self.data = self.data[:-partial]
|
||||||
elif pad:
|
elif pad:
|
||||||
self.data += '\0' * (self.blocksize - partial)
|
self.data += '\0' * (self.blocksize - partial)
|
||||||
|
padded = True
|
||||||
else:
|
else:
|
||||||
raise ValueError(("data for DataImage must be multiple of %d bytes "
|
raise ValueError(("data for DataImage must be multiple of %d bytes "
|
||||||
"unless trim or pad is specified") %
|
"unless trim or pad is specified") %
|
||||||
@@ -120,14 +122,23 @@ class DataImage(Image):
|
|||||||
|
|
||||||
self.total_blocks = len(self.data) / self.blocksize
|
self.total_blocks = len(self.data) / self.blocksize
|
||||||
self.care_map = RangeSet(data=(0, self.total_blocks))
|
self.care_map = RangeSet(data=(0, self.total_blocks))
|
||||||
self.clobbered_blocks = RangeSet()
|
# When the last block is padded, we always write the whole block even for
|
||||||
|
# incremental OTAs. Because otherwise the last block may get skipped if
|
||||||
|
# unchanged for an incremental, but would fail the post-install
|
||||||
|
# verification if it has non-zero contents in the padding bytes.
|
||||||
|
# Bug: 23828506
|
||||||
|
if padded:
|
||||||
|
self.clobbered_blocks = RangeSet(
|
||||||
|
data=(self.total_blocks-1, self.total_blocks))
|
||||||
|
else:
|
||||||
|
self.clobbered_blocks = RangeSet()
|
||||||
self.extended = RangeSet()
|
self.extended = RangeSet()
|
||||||
|
|
||||||
zero_blocks = []
|
zero_blocks = []
|
||||||
nonzero_blocks = []
|
nonzero_blocks = []
|
||||||
reference = '\0' * self.blocksize
|
reference = '\0' * self.blocksize
|
||||||
|
|
||||||
for i in range(self.total_blocks):
|
for i in range(self.total_blocks-1 if padded else self.total_blocks):
|
||||||
d = self.data[i*self.blocksize : (i+1)*self.blocksize]
|
d = self.data[i*self.blocksize : (i+1)*self.blocksize]
|
||||||
if d == reference:
|
if d == reference:
|
||||||
zero_blocks.append(i)
|
zero_blocks.append(i)
|
||||||
@@ -139,14 +150,18 @@ class DataImage(Image):
|
|||||||
self.file_map = {"__ZERO": RangeSet(zero_blocks),
|
self.file_map = {"__ZERO": RangeSet(zero_blocks),
|
||||||
"__NONZERO": RangeSet(nonzero_blocks)}
|
"__NONZERO": RangeSet(nonzero_blocks)}
|
||||||
|
|
||||||
|
if self.clobbered_blocks:
|
||||||
|
self.file_map["__COPY"] = self.clobbered_blocks
|
||||||
|
|
||||||
def ReadRangeSet(self, ranges):
|
def ReadRangeSet(self, ranges):
|
||||||
return [self.data[s*self.blocksize:e*self.blocksize] for (s, e) in ranges]
|
return [self.data[s*self.blocksize:e*self.blocksize] for (s, e) in ranges]
|
||||||
|
|
||||||
def TotalSha1(self, include_clobbered_blocks=False):
|
def TotalSha1(self, include_clobbered_blocks=False):
|
||||||
# DataImage always carries empty clobbered_blocks, so
|
if not include_clobbered_blocks:
|
||||||
# include_clobbered_blocks can be ignored.
|
ranges = self.care_map.subtract(self.clobbered_blocks)
|
||||||
assert self.clobbered_blocks.size() == 0
|
return sha1(self.ReadRangeSet(ranges)).hexdigest()
|
||||||
return sha1(self.data).hexdigest()
|
else:
|
||||||
|
return sha1(self.data).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
class Transfer(object):
|
class Transfer(object):
|
||||||
|
Reference in New Issue
Block a user