Merge "full support for OTA of vendor partitions"
This commit is contained in:
@@ -1335,8 +1335,10 @@ endif
|
|||||||
$(hide) ./build/tools/releasetools/make_recovery_patch $(zip_root) $(zip_root)
|
$(hide) ./build/tools/releasetools/make_recovery_patch $(zip_root) $(zip_root)
|
||||||
@# Zip everything up, preserving symlinks
|
@# Zip everything up, preserving symlinks
|
||||||
$(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
|
$(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
|
||||||
@# Run fs_config on all the system, boot ramdisk, and recovery ramdisk files in the zip, and save the output
|
@# Run fs_config on all the system, vendor, boot ramdisk,
|
||||||
|
@# and recovery ramdisk files in the zip, and save the output
|
||||||
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/filesystem_config.txt
|
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/filesystem_config.txt
|
||||||
|
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="VENDOR/" } /^VENDOR\// {print "vendor/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/vendor_filesystem_config.txt
|
||||||
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/boot_filesystem_config.txt
|
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/boot_filesystem_config.txt
|
||||||
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt
|
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt
|
||||||
$(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt)
|
$(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt)
|
||||||
|
@@ -1008,14 +1008,14 @@ def XZ(path):
|
|||||||
p.communicate()
|
p.communicate()
|
||||||
assert p.returncode == 0, "Couldn't compress patch"
|
assert p.returncode == 0, "Couldn't compress patch"
|
||||||
|
|
||||||
def MakeSystemPatch(source_file, target_file):
|
def MakePartitionPatch(source_file, target_file, partition):
|
||||||
with tempfile.NamedTemporaryFile() as output_file:
|
with tempfile.NamedTemporaryFile() as output_file:
|
||||||
XDelta3(source_file.name, target_file.name, output_file.name)
|
XDelta3(source_file.name, target_file.name, output_file.name)
|
||||||
XZ(output_file.name)
|
XZ(output_file.name)
|
||||||
with open(output_file.name + ".xz") as patch_file:
|
with open(output_file.name + ".xz") as patch_file:
|
||||||
patch_data = patch_file.read()
|
patch_data = patch_file.read()
|
||||||
os.unlink(patch_file.name)
|
os.unlink(patch_file.name)
|
||||||
return File("system.muimg.p", patch_data)
|
return File(partition + ".muimg.p", patch_data)
|
||||||
|
|
||||||
def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img,
|
def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img,
|
||||||
info_dict=None):
|
info_dict=None):
|
||||||
|
@@ -203,11 +203,10 @@ class EdifyGenerator(object):
|
|||||||
p.device, p.length, p.mount_point))
|
p.device, p.length, p.mount_point))
|
||||||
|
|
||||||
def WipeBlockDevice(self, partition):
|
def WipeBlockDevice(self, partition):
|
||||||
if partition != "/system":
|
if partition not in ("/system", "/vendor"):
|
||||||
raise ValueError(("WipeBlockDevice currently only works "
|
raise ValueError(("WipeBlockDevice doesn't work on %s\n") % (partition,))
|
||||||
"on /system, not %s\n") % (partition,))
|
|
||||||
fstab = self.info.get("fstab", None)
|
fstab = self.info.get("fstab", None)
|
||||||
size = self.info.get("system_size", None)
|
size = self.info.get(partition.lstrip("/") + "_size", None)
|
||||||
device = fstab[partition].device
|
device = fstab[partition].device
|
||||||
|
|
||||||
self.script.append('wipe_block_device("%s", %s);' % (device, size))
|
self.script.append('wipe_block_device("%s", %s);' % (device, size))
|
||||||
|
@@ -59,9 +59,21 @@ def AddSystem(output_zip, sparse=True):
|
|||||||
data = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict, sparse=sparse)
|
data = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict, sparse=sparse)
|
||||||
common.ZipWriteStr(output_zip, "system.img", data)
|
common.ZipWriteStr(output_zip, "system.img", data)
|
||||||
|
|
||||||
|
|
||||||
def BuildSystem(input_dir, info_dict, sparse=True, map_file=None):
|
def BuildSystem(input_dir, info_dict, sparse=True, map_file=None):
|
||||||
print "creating system.img..."
|
return CreateImage(input_dir, info_dict, "system",
|
||||||
|
sparse=sparse, map_file=map_file)
|
||||||
|
|
||||||
|
def AddVendor(output_zip, sparse=True):
|
||||||
|
data = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict, sparse=sparse)
|
||||||
|
common.ZipWriteStr(output_zip, "vendor.img", data)
|
||||||
|
|
||||||
|
def BuildVendor(input_dir, info_dict, sparse=True, map_file=None):
|
||||||
|
return CreateImage(input_dir, info_dict, "vendor",
|
||||||
|
sparse=sparse, map_file=map_file)
|
||||||
|
|
||||||
|
|
||||||
|
def CreateImage(input_dir, info_dict, what, sparse=True, map_file=None):
|
||||||
|
print "creating " + what + ".img..."
|
||||||
|
|
||||||
img = tempfile.NamedTemporaryFile()
|
img = tempfile.NamedTemporaryFile()
|
||||||
|
|
||||||
@@ -69,8 +81,8 @@ def BuildSystem(input_dir, info_dict, sparse=True, map_file=None):
|
|||||||
# mkyaffs2image. It wants "system" but we have a directory named
|
# mkyaffs2image. It wants "system" but we have a directory named
|
||||||
# "SYSTEM", so create a symlink.
|
# "SYSTEM", so create a symlink.
|
||||||
try:
|
try:
|
||||||
os.symlink(os.path.join(input_dir, "SYSTEM"),
|
os.symlink(os.path.join(input_dir, what.upper()),
|
||||||
os.path.join(input_dir, "system"))
|
os.path.join(input_dir, what))
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
# bogus error on my mac version?
|
# bogus error on my mac version?
|
||||||
# File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem
|
# File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem
|
||||||
@@ -79,22 +91,28 @@ def BuildSystem(input_dir, info_dict, sparse=True, map_file=None):
|
|||||||
if (e.errno == errno.EEXIST):
|
if (e.errno == errno.EEXIST):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
image_props = build_image.ImagePropFromGlobalDict(info_dict, "system")
|
image_props = build_image.ImagePropFromGlobalDict(info_dict, what)
|
||||||
fstab = info_dict["fstab"]
|
fstab = info_dict["fstab"]
|
||||||
if fstab:
|
if fstab:
|
||||||
image_props["fs_type" ] = fstab["/system"].fs_type
|
image_props["fs_type" ] = fstab["/" + what].fs_type
|
||||||
|
|
||||||
fs_config = os.path.join(input_dir, "META/filesystem_config.txt")
|
if what == "system":
|
||||||
|
fs_config_prefix = ""
|
||||||
|
else:
|
||||||
|
fs_config_prefix = what + "_"
|
||||||
|
|
||||||
|
fs_config = os.path.join(
|
||||||
|
input_dir, "META/" + fs_config_prefix + "filesystem_config.txt")
|
||||||
if not os.path.exists(fs_config): fs_config = None
|
if not os.path.exists(fs_config): fs_config = None
|
||||||
|
|
||||||
fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts")
|
fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts")
|
||||||
if not os.path.exists(fc_config): fc_config = None
|
if not os.path.exists(fc_config): fc_config = None
|
||||||
|
|
||||||
succ = build_image.BuildImage(os.path.join(input_dir, "system"),
|
succ = build_image.BuildImage(os.path.join(input_dir, what),
|
||||||
image_props, img.name,
|
image_props, img.name,
|
||||||
fs_config=fs_config,
|
fs_config=fs_config,
|
||||||
fc_config=fc_config)
|
fc_config=fc_config)
|
||||||
assert succ, "build system.img image failed"
|
assert succ, "build " + what + ".img image failed"
|
||||||
|
|
||||||
mapdata = None
|
mapdata = None
|
||||||
|
|
||||||
@@ -104,7 +122,7 @@ def BuildSystem(input_dir, info_dict, sparse=True, map_file=None):
|
|||||||
else:
|
else:
|
||||||
success, name = build_image.UnsparseImage(img.name, replace=False)
|
success, name = build_image.UnsparseImage(img.name, replace=False)
|
||||||
if not success:
|
if not success:
|
||||||
assert False, "unsparsing system.img failed"
|
assert False, "unsparsing " + what + ".img failed"
|
||||||
|
|
||||||
if map_file:
|
if map_file:
|
||||||
mmap = tempfile.NamedTemporaryFile()
|
mmap = tempfile.NamedTemporaryFile()
|
||||||
@@ -131,45 +149,6 @@ def BuildSystem(input_dir, info_dict, sparse=True, map_file=None):
|
|||||||
return mapdata, data
|
return mapdata, data
|
||||||
|
|
||||||
|
|
||||||
def AddVendor(output_zip):
|
|
||||||
"""Turn the contents of VENDOR into vendor.img and store it in
|
|
||||||
output_zip."""
|
|
||||||
|
|
||||||
image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict,
|
|
||||||
"vendor")
|
|
||||||
# The build system has to explicitly request for vendor.img.
|
|
||||||
if "fs_type" not in image_props:
|
|
||||||
return
|
|
||||||
|
|
||||||
print "creating vendor.img..."
|
|
||||||
|
|
||||||
img = tempfile.NamedTemporaryFile()
|
|
||||||
|
|
||||||
# The name of the directory it is making an image out of matters to
|
|
||||||
# mkyaffs2image. It wants "vendor" but we have a directory named
|
|
||||||
# "VENDOR", so create a symlink or an empty directory if VENDOR does not
|
|
||||||
# exist.
|
|
||||||
if not os.path.exists(os.path.join(OPTIONS.input_tmp, "vendor")):
|
|
||||||
if os.path.exists(os.path.join(OPTIONS.input_tmp, "VENDOR")):
|
|
||||||
os.symlink(os.path.join(OPTIONS.input_tmp, "VENDOR"),
|
|
||||||
os.path.join(OPTIONS.input_tmp, "vendor"))
|
|
||||||
else:
|
|
||||||
os.mkdir(os.path.join(OPTIONS.input_tmp, "vendor"))
|
|
||||||
|
|
||||||
img = tempfile.NamedTemporaryFile()
|
|
||||||
|
|
||||||
fstab = OPTIONS.info_dict["fstab"]
|
|
||||||
if fstab:
|
|
||||||
image_props["fs_type" ] = fstab["/vendor"].fs_type
|
|
||||||
succ = build_image.BuildImage(os.path.join(OPTIONS.input_tmp, "vendor"),
|
|
||||||
image_props, img.name)
|
|
||||||
assert succ, "build vendor.img image failed"
|
|
||||||
|
|
||||||
common.CheckSize(img.name, "vendor.img", OPTIONS.info_dict)
|
|
||||||
output_zip.write(img.name, "vendor.img")
|
|
||||||
img.close()
|
|
||||||
|
|
||||||
|
|
||||||
def AddUserdata(output_zip):
|
def AddUserdata(output_zip):
|
||||||
"""Create an empty userdata image and store it in output_zip."""
|
"""Create an empty userdata image and store it in output_zip."""
|
||||||
|
|
||||||
@@ -287,10 +266,21 @@ def main(argv):
|
|||||||
if recovery_image:
|
if recovery_image:
|
||||||
recovery_image.AddToZip(output_zip)
|
recovery_image.AddToZip(output_zip)
|
||||||
|
|
||||||
|
def banner(s):
|
||||||
|
print "\n\n++++ " + s + " ++++\n\n"
|
||||||
|
|
||||||
if not bootable_only:
|
if not bootable_only:
|
||||||
|
banner("AddSystem")
|
||||||
AddSystem(output_zip)
|
AddSystem(output_zip)
|
||||||
AddVendor(output_zip)
|
try:
|
||||||
|
input_zip.getinfo("VENDOR/")
|
||||||
|
banner("AddVendor")
|
||||||
|
AddVendor(output_zip)
|
||||||
|
except KeyError:
|
||||||
|
pass # no vendor partition for this device
|
||||||
|
banner("AddUserdata")
|
||||||
AddUserdata(output_zip)
|
AddUserdata(output_zip)
|
||||||
|
banner("AddCache")
|
||||||
AddCache(output_zip)
|
AddCache(output_zip)
|
||||||
CopyInfo(output_zip)
|
CopyInfo(output_zip)
|
||||||
|
|
||||||
|
@@ -159,50 +159,21 @@ def ClosestFileMatch(src, tgtfiles, existing):
|
|||||||
return result
|
return result
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class Item:
|
class ItemSet:
|
||||||
"""Items represent the metadata (user, group, mode) of files and
|
def __init__(self, partition, fs_config):
|
||||||
directories in the system image."""
|
self.partition = partition
|
||||||
ITEMS = {}
|
self.fs_config = fs_config
|
||||||
def __init__(self, name, dir=False):
|
self.ITEMS = {}
|
||||||
self.name = name
|
|
||||||
self.uid = None
|
|
||||||
self.gid = None
|
|
||||||
self.mode = None
|
|
||||||
self.selabel = None
|
|
||||||
self.capabilities = None
|
|
||||||
self.dir = dir
|
|
||||||
|
|
||||||
if name:
|
def Get(self, name, dir=False):
|
||||||
self.parent = Item.Get(os.path.dirname(name), dir=True)
|
if name not in self.ITEMS:
|
||||||
self.parent.children.append(self)
|
self.ITEMS[name] = Item(self, name, dir=dir)
|
||||||
else:
|
return self.ITEMS[name]
|
||||||
self.parent = None
|
|
||||||
if dir:
|
|
||||||
self.children = []
|
|
||||||
|
|
||||||
def Dump(self, indent=0):
|
|
||||||
if self.uid is not None:
|
|
||||||
print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
|
|
||||||
else:
|
|
||||||
print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
|
|
||||||
if self.dir:
|
|
||||||
print "%s%s" % (" "*indent, self.descendants)
|
|
||||||
print "%s%s" % (" "*indent, self.best_subtree)
|
|
||||||
for i in self.children:
|
|
||||||
i.Dump(indent=indent+1)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def Get(cls, name, dir=False):
|
|
||||||
if name not in cls.ITEMS:
|
|
||||||
cls.ITEMS[name] = Item(name, dir=dir)
|
|
||||||
return cls.ITEMS[name]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def GetMetadata(cls, input_zip):
|
|
||||||
|
|
||||||
|
def GetMetadata(self, input_zip):
|
||||||
# The target_files contains a record of what the uid,
|
# The target_files contains a record of what the uid,
|
||||||
# gid, and mode are supposed to be.
|
# gid, and mode are supposed to be.
|
||||||
output = input_zip.read("META/filesystem_config.txt")
|
output = input_zip.read(self.fs_config)
|
||||||
|
|
||||||
for line in output.split("\n"):
|
for line in output.split("\n"):
|
||||||
if not line: continue
|
if not line: continue
|
||||||
@@ -220,7 +191,7 @@ class Item:
|
|||||||
if key == "capabilities":
|
if key == "capabilities":
|
||||||
capabilities = value
|
capabilities = value
|
||||||
|
|
||||||
i = cls.ITEMS.get(name, None)
|
i = self.ITEMS.get(name, None)
|
||||||
if i is not None:
|
if i is not None:
|
||||||
i.uid = int(uid)
|
i.uid = int(uid)
|
||||||
i.gid = int(gid)
|
i.gid = int(gid)
|
||||||
@@ -231,11 +202,44 @@ class Item:
|
|||||||
i.children.sort(key=lambda i: i.name)
|
i.children.sort(key=lambda i: i.name)
|
||||||
|
|
||||||
# set metadata for the files generated by this script.
|
# set metadata for the files generated by this script.
|
||||||
i = cls.ITEMS.get("system/recovery-from-boot.p", None)
|
i = self.ITEMS.get("system/recovery-from-boot.p", None)
|
||||||
if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
|
if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
|
||||||
i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
|
i = self.ITEMS.get("system/etc/install-recovery.sh", None)
|
||||||
if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
|
if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
|
||||||
|
|
||||||
|
|
||||||
|
class Item:
|
||||||
|
"""Items represent the metadata (user, group, mode) of files and
|
||||||
|
directories in the system image."""
|
||||||
|
def __init__(self, itemset, name, dir=False):
|
||||||
|
self.itemset = itemset
|
||||||
|
self.name = name
|
||||||
|
self.uid = None
|
||||||
|
self.gid = None
|
||||||
|
self.mode = None
|
||||||
|
self.selabel = None
|
||||||
|
self.capabilities = None
|
||||||
|
self.dir = dir
|
||||||
|
|
||||||
|
if name:
|
||||||
|
self.parent = itemset.Get(os.path.dirname(name), dir=True)
|
||||||
|
self.parent.children.append(self)
|
||||||
|
else:
|
||||||
|
self.parent = None
|
||||||
|
if dir:
|
||||||
|
self.children = []
|
||||||
|
|
||||||
|
def Dump(self, indent=0):
|
||||||
|
if self.uid is not None:
|
||||||
|
print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
|
||||||
|
else:
|
||||||
|
print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
|
||||||
|
if self.dir:
|
||||||
|
print "%s%s" % (" "*indent, self.descendants)
|
||||||
|
print "%s%s" % (" "*indent, self.best_subtree)
|
||||||
|
for i in self.children:
|
||||||
|
i.Dump(indent=indent+1)
|
||||||
|
|
||||||
def CountChildMetadata(self):
|
def CountChildMetadata(self):
|
||||||
"""Count up the (uid, gid, mode, selabel, capabilities) tuples for
|
"""Count up the (uid, gid, mode, selabel, capabilities) tuples for
|
||||||
all children and determine the best strategy for using set_perm_recursive and
|
all children and determine the best strategy for using set_perm_recursive and
|
||||||
@@ -320,9 +324,8 @@ class Item:
|
|||||||
recurse(self, (-1, -1, -1, -1, None, None))
|
recurse(self, (-1, -1, -1, -1, None, None))
|
||||||
|
|
||||||
|
|
||||||
def CopySystemFiles(input_zip, output_zip=None,
|
def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
|
||||||
substitute=None):
|
"""Copies files for the partition in the input zip to the output
|
||||||
"""Copies files underneath system/ in the input zip to the output
|
|
||||||
zip. Populates the Item class with their metadata, and returns a
|
zip. Populates the Item class with their metadata, and returns a
|
||||||
list of symlinks. output_zip may be None, in which case the copy is
|
list of symlinks. output_zip may be None, in which case the copy is
|
||||||
skipped (but the other side effects still happen). substitute is an
|
skipped (but the other side effects still happen). substitute is an
|
||||||
@@ -332,15 +335,17 @@ def CopySystemFiles(input_zip, output_zip=None,
|
|||||||
|
|
||||||
symlinks = []
|
symlinks = []
|
||||||
|
|
||||||
|
partition = itemset.partition
|
||||||
|
|
||||||
for info in input_zip.infolist():
|
for info in input_zip.infolist():
|
||||||
if info.filename.startswith("SYSTEM/"):
|
if info.filename.startswith(partition.upper() + "/"):
|
||||||
basefilename = info.filename[7:]
|
basefilename = info.filename[7:]
|
||||||
if IsSymlink(info):
|
if IsSymlink(info):
|
||||||
symlinks.append((input_zip.read(info.filename),
|
symlinks.append((input_zip.read(info.filename),
|
||||||
"/system/" + basefilename))
|
"/" + partition + "/" + basefilename))
|
||||||
else:
|
else:
|
||||||
info2 = copy.copy(info)
|
info2 = copy.copy(info)
|
||||||
fn = info2.filename = "system/" + basefilename
|
fn = info2.filename = partition + "/" + basefilename
|
||||||
if substitute and fn in substitute and substitute[fn] is None:
|
if substitute and fn in substitute and substitute[fn] is None:
|
||||||
continue
|
continue
|
||||||
if output_zip is not None:
|
if output_zip is not None:
|
||||||
@@ -350,9 +355,9 @@ def CopySystemFiles(input_zip, output_zip=None,
|
|||||||
data = input_zip.read(info.filename)
|
data = input_zip.read(info.filename)
|
||||||
output_zip.writestr(info2, data)
|
output_zip.writestr(info2, data)
|
||||||
if fn.endswith("/"):
|
if fn.endswith("/"):
|
||||||
Item.Get(fn[:-1], dir=True)
|
itemset.Get(fn[:-1], dir=True)
|
||||||
else:
|
else:
|
||||||
Item.Get(fn, dir=False)
|
itemset.Get(fn, dir=False)
|
||||||
|
|
||||||
symlinks.sort()
|
symlinks.sort()
|
||||||
return symlinks
|
return symlinks
|
||||||
@@ -387,6 +392,13 @@ def HasRecoveryPatch(target_files_zip):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def HasVendorPartition(target_files_zip):
|
||||||
|
try:
|
||||||
|
target_files_zip.getinfo("VENDOR/")
|
||||||
|
return True
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
|
||||||
def GetOemProperty(name, oem_props, oem_dict, info_dict):
|
def GetOemProperty(name, oem_props, oem_dict, info_dict):
|
||||||
if oem_props is not None and name in oem_props:
|
if oem_props is not None and name in oem_props:
|
||||||
return oem_dict[name]
|
return oem_dict[name]
|
||||||
@@ -489,10 +501,13 @@ else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
|
|||||||
|
|
||||||
if OPTIONS.wipe_user_data:
|
if OPTIONS.wipe_user_data:
|
||||||
system_progress -= 0.1
|
system_progress -= 0.1
|
||||||
|
if HasVendorPartition(input_zip):
|
||||||
|
system_progress -= 0.1
|
||||||
|
|
||||||
if "selinux_fc" in OPTIONS.info_dict:
|
if "selinux_fc" in OPTIONS.info_dict:
|
||||||
WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
|
WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
|
||||||
|
|
||||||
|
system_items = ItemSet("system", "META/filesystem_config.txt")
|
||||||
script.ShowProgress(system_progress, 0)
|
script.ShowProgress(system_progress, 0)
|
||||||
if block_based:
|
if block_based:
|
||||||
mapdata, data = img_from_target_files.BuildSystem(
|
mapdata, data = img_from_target_files.BuildSystem(
|
||||||
@@ -510,7 +525,7 @@ else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
|
|||||||
script.UnpackPackageDir("recovery", "/system")
|
script.UnpackPackageDir("recovery", "/system")
|
||||||
script.UnpackPackageDir("system", "/system")
|
script.UnpackPackageDir("system", "/system")
|
||||||
|
|
||||||
symlinks = CopySystemFiles(input_zip, output_zip)
|
symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
|
||||||
script.MakeSymlinks(symlinks)
|
script.MakeSymlinks(symlinks)
|
||||||
|
|
||||||
boot_img = common.GetBootableImage("boot.img", "boot.img",
|
boot_img = common.GetBootableImage("boot.img", "boot.img",
|
||||||
@@ -519,13 +534,37 @@ else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
|
|||||||
if not block_based:
|
if not block_based:
|
||||||
def output_sink(fn, data):
|
def output_sink(fn, data):
|
||||||
common.ZipWriteStr(output_zip, "recovery/" + fn, data)
|
common.ZipWriteStr(output_zip, "recovery/" + fn, data)
|
||||||
Item.Get("system/" + fn, dir=False)
|
system_items.Get("system/" + fn, dir=False)
|
||||||
|
|
||||||
common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
|
common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
|
||||||
recovery_img, boot_img)
|
recovery_img, boot_img)
|
||||||
|
|
||||||
Item.GetMetadata(input_zip)
|
system_items.GetMetadata(input_zip)
|
||||||
Item.Get("system").SetPermissions(script)
|
system_items.Get("system").SetPermissions(script)
|
||||||
|
|
||||||
|
if HasVendorPartition(input_zip):
|
||||||
|
vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
|
||||||
|
script.ShowProgress(0.1, 0)
|
||||||
|
|
||||||
|
if block_based:
|
||||||
|
mapdata, data = img_from_target_files.BuildVendor(
|
||||||
|
OPTIONS.input_tmp, OPTIONS.info_dict,
|
||||||
|
sparse=False, map_file=True)
|
||||||
|
|
||||||
|
common.ZipWriteStr(output_zip, "vendor.map", mapdata)
|
||||||
|
common.ZipWriteStr(output_zip, "vendor.muimg", data)
|
||||||
|
script.WipeBlockDevice("/vendor")
|
||||||
|
script.WriteRawImage("/vendor", "vendor.muimg", mapfn="vendor.map")
|
||||||
|
else:
|
||||||
|
script.FormatPartition("/vendor")
|
||||||
|
script.Mount("/vendor")
|
||||||
|
script.UnpackPackageDir("vendor", "/vendor")
|
||||||
|
|
||||||
|
symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
|
||||||
|
script.MakeSymlinks(symlinks)
|
||||||
|
|
||||||
|
vendor_items.GetMetadata(input_zip)
|
||||||
|
vendor_items.Get("vendor").SetPermissions(script)
|
||||||
|
|
||||||
common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
|
common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
|
||||||
common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
|
common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
|
||||||
@@ -571,14 +610,15 @@ def WriteMetadata(metadata, output_zip):
|
|||||||
"".join(["%s=%s\n" % kv
|
"".join(["%s=%s\n" % kv
|
||||||
for kv in sorted(metadata.iteritems())]))
|
for kv in sorted(metadata.iteritems())]))
|
||||||
|
|
||||||
def LoadSystemFiles(z):
|
def LoadPartitionFiles(z, partition):
|
||||||
"""Load all the files from SYSTEM/... in a given target-files
|
"""Load all the files from the given partition in a given target-files
|
||||||
ZipFile, and return a dict of {filename: File object}."""
|
ZipFile, and return a dict of {filename: File object}."""
|
||||||
out = {}
|
out = {}
|
||||||
|
prefix = partition.upper() + "/"
|
||||||
for info in z.infolist():
|
for info in z.infolist():
|
||||||
if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
|
if info.filename.startswith(prefix) and not IsSymlink(info):
|
||||||
basefilename = info.filename[7:]
|
basefilename = info.filename[7:]
|
||||||
fn = "system/" + basefilename
|
fn = partition + "/" + basefilename
|
||||||
data = z.read(info.filename)
|
data = z.read(info.filename)
|
||||||
out[fn] = common.File(fn, data)
|
out[fn] = common.File(fn, data)
|
||||||
return out
|
return out
|
||||||
@@ -602,6 +642,45 @@ def AddToKnownPaths(filename, known_paths):
|
|||||||
known_paths.add(path)
|
known_paths.add(path)
|
||||||
dirs.pop()
|
dirs.pop()
|
||||||
|
|
||||||
|
class BlockDifference:
|
||||||
|
def __init__(self, partition, builder, output_zip):
|
||||||
|
with tempfile.NamedTemporaryFile() as src_file:
|
||||||
|
with tempfile.NamedTemporaryFile() as tgt_file:
|
||||||
|
print "building source " + partition + " image..."
|
||||||
|
src_file = tempfile.NamedTemporaryFile()
|
||||||
|
src_mapdata, src_data = builder(OPTIONS.source_tmp,
|
||||||
|
OPTIONS.source_info_dict,
|
||||||
|
sparse=False, map_file=True)
|
||||||
|
|
||||||
|
self.src_sha1 = sha1(src_data).hexdigest()
|
||||||
|
print "source " + partition + " sha1:", self.src_sha1
|
||||||
|
src_file.write(src_data)
|
||||||
|
|
||||||
|
print "building target " + partition + " image..."
|
||||||
|
tgt_file = tempfile.NamedTemporaryFile()
|
||||||
|
tgt_mapdata, tgt_data = builder(OPTIONS.target_tmp,
|
||||||
|
OPTIONS.target_info_dict,
|
||||||
|
sparse=False, map_file=True)
|
||||||
|
self.tgt_sha1 = sha1(tgt_data).hexdigest()
|
||||||
|
print "target " + partition + " sha1:", self.tgt_sha1
|
||||||
|
tgt_len = len(tgt_data)
|
||||||
|
tgt_file.write(tgt_data)
|
||||||
|
|
||||||
|
system_type, self.device = common.GetTypeAndDevice("/" + partition,
|
||||||
|
OPTIONS.info_dict)
|
||||||
|
self.patch = common.MakePartitionPatch(src_file, tgt_file, partition)
|
||||||
|
|
||||||
|
TestBlockPatch(src_data, src_mapdata, self.patch.data,
|
||||||
|
tgt_mapdata, self.tgt_sha1)
|
||||||
|
src_data = None
|
||||||
|
tgt_data = None
|
||||||
|
|
||||||
|
self.patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
|
||||||
|
self.src_mapfilename = self.patch.name + ".src.map"
|
||||||
|
common.ZipWriteStr(output_zip, self.src_mapfilename, src_mapdata)
|
||||||
|
self.tgt_mapfilename = self.patch.name + ".tgt.map"
|
||||||
|
common.ZipWriteStr(output_zip, self.tgt_mapfilename, tgt_mapdata)
|
||||||
|
|
||||||
def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
||||||
source_version = OPTIONS.source_info_dict["recovery_api_version"]
|
source_version = OPTIONS.source_info_dict["recovery_api_version"]
|
||||||
target_version = OPTIONS.target_info_dict["recovery_api_version"]
|
target_version = OPTIONS.target_info_dict["recovery_api_version"]
|
||||||
@@ -648,40 +727,13 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
|||||||
"/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
|
"/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
|
||||||
updating_recovery = (source_recovery.data != target_recovery.data)
|
updating_recovery = (source_recovery.data != target_recovery.data)
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile() as src_file:
|
system_diff = BlockDifference("system", img_from_target_files.BuildSystem,
|
||||||
with tempfile.NamedTemporaryFile() as tgt_file:
|
output_zip)
|
||||||
print "building source system image..."
|
if HasVendorPartition(target_zip):
|
||||||
src_file = tempfile.NamedTemporaryFile()
|
if not HasVendorPartition(source_zip):
|
||||||
src_mapdata, src_data = img_from_target_files.BuildSystem(
|
raise RuntimeError("can't generate incremental that adds /vendor")
|
||||||
OPTIONS.source_tmp, OPTIONS.source_info_dict,
|
vendor_diff = BlockDifference("vendor", img_from_target_files.BuildVendor,
|
||||||
sparse=False, map_file=True)
|
output_zip)
|
||||||
|
|
||||||
src_sys_sha1 = sha1(src_data).hexdigest()
|
|
||||||
print "source system sha1:", src_sys_sha1
|
|
||||||
src_file.write(src_data)
|
|
||||||
|
|
||||||
print "building target system image..."
|
|
||||||
tgt_file = tempfile.NamedTemporaryFile()
|
|
||||||
tgt_mapdata, tgt_data = img_from_target_files.BuildSystem(
|
|
||||||
OPTIONS.target_tmp, OPTIONS.target_info_dict,
|
|
||||||
sparse=False, map_file=True)
|
|
||||||
tgt_sys_sha1 = sha1(tgt_data).hexdigest()
|
|
||||||
print "target system sha1:", tgt_sys_sha1
|
|
||||||
tgt_sys_len = len(tgt_data)
|
|
||||||
tgt_file.write(tgt_data)
|
|
||||||
|
|
||||||
system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
|
|
||||||
system_patch = common.MakeSystemPatch(src_file, tgt_file)
|
|
||||||
|
|
||||||
TestBlockPatch(src_data, src_mapdata, system_patch.data, tgt_mapdata, tgt_sys_sha1)
|
|
||||||
src_data = None
|
|
||||||
tgt_data = None
|
|
||||||
|
|
||||||
system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
|
|
||||||
src_mapfilename = system_patch.name + ".src.map"
|
|
||||||
common.ZipWriteStr(output_zip, src_mapfilename, src_mapdata)
|
|
||||||
tgt_mapfilename = system_patch.name + ".tgt.map"
|
|
||||||
common.ZipWriteStr(output_zip, tgt_mapfilename, tgt_mapdata)
|
|
||||||
|
|
||||||
oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
|
oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
|
||||||
oem_dict = None
|
oem_dict = None
|
||||||
@@ -774,12 +826,23 @@ else
|
|||||||
|
|
||||||
device_specific.IncrementalOTA_InstallBegin()
|
device_specific.IncrementalOTA_InstallBegin()
|
||||||
|
|
||||||
|
if HasVendorPartition(target_zip):
|
||||||
|
script.Print("Patching vendor image...")
|
||||||
|
script.ShowProgress(0.1, 0)
|
||||||
|
script.Syspatch(vendor_diff.device,
|
||||||
|
vendor_diff.tgt_mapfilename, vendor_diff.tgt_sha1,
|
||||||
|
vendor_diff.src_mapfilename, vendor_diff.src_sha1,
|
||||||
|
vendor_diff.patch.name)
|
||||||
|
sys_progress = 0.8
|
||||||
|
else:
|
||||||
|
sys_progress = 0.9
|
||||||
|
|
||||||
script.Print("Patching system image...")
|
script.Print("Patching system image...")
|
||||||
script.ShowProgress(0.9, 0)
|
script.ShowProgress(sys_progress, 0)
|
||||||
script.Syspatch(system_device,
|
script.Syspatch(system_diff.device,
|
||||||
tgt_mapfilename, tgt_sys_sha1,
|
system_diff.tgt_mapfilename, system_diff.tgt_sha1,
|
||||||
src_mapfilename, src_sys_sha1,
|
system_diff.src_mapfilename, system_diff.src_sha1,
|
||||||
system_patch.name)
|
system_diff.patch.name)
|
||||||
|
|
||||||
if OPTIONS.two_step:
|
if OPTIONS.two_step:
|
||||||
common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
|
common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
|
||||||
@@ -881,6 +944,127 @@ def TestBlockPatch(src_muimg, src_map, patch_data, tgt_map, tgt_sha1):
|
|||||||
print "test of system image patch succeeded"
|
print "test of system image patch succeeded"
|
||||||
|
|
||||||
|
|
||||||
|
class FileDifference:
|
||||||
|
def __init__(self, partition, source_zip, target_zip, output_zip):
|
||||||
|
print "Loading target..."
|
||||||
|
self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
|
||||||
|
print "Loading source..."
|
||||||
|
self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
|
||||||
|
|
||||||
|
self.verbatim_targets = verbatim_targets = []
|
||||||
|
self.patch_list = patch_list = []
|
||||||
|
diffs = []
|
||||||
|
self.renames = renames = {}
|
||||||
|
known_paths = set()
|
||||||
|
largest_source_size = 0
|
||||||
|
|
||||||
|
matching_file_cache = {}
|
||||||
|
for fn, sf in source_data.items():
|
||||||
|
assert fn == sf.name
|
||||||
|
matching_file_cache["path:" + fn] = sf
|
||||||
|
if fn in target_data.keys():
|
||||||
|
AddToKnownPaths(fn, known_paths)
|
||||||
|
# Only allow eligibility for filename/sha matching
|
||||||
|
# if there isn't a perfect path match.
|
||||||
|
if target_data.get(sf.name) is None:
|
||||||
|
matching_file_cache["file:" + fn.split("/")[-1]] = sf
|
||||||
|
matching_file_cache["sha:" + sf.sha1] = sf
|
||||||
|
|
||||||
|
for fn in sorted(target_data.keys()):
|
||||||
|
tf = target_data[fn]
|
||||||
|
assert fn == tf.name
|
||||||
|
sf = ClosestFileMatch(tf, matching_file_cache, renames)
|
||||||
|
if sf is not None and sf.name != tf.name:
|
||||||
|
print "File has moved from " + sf.name + " to " + tf.name
|
||||||
|
renames[sf.name] = tf
|
||||||
|
|
||||||
|
if sf is None or fn in OPTIONS.require_verbatim:
|
||||||
|
# This file should be included verbatim
|
||||||
|
if fn in OPTIONS.prohibit_verbatim:
|
||||||
|
raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
|
||||||
|
print "send", fn, "verbatim"
|
||||||
|
tf.AddToZip(output_zip)
|
||||||
|
verbatim_targets.append((fn, tf.size))
|
||||||
|
if fn in target_data.keys():
|
||||||
|
AddToKnownPaths(fn, known_paths)
|
||||||
|
elif tf.sha1 != sf.sha1:
|
||||||
|
# File is different; consider sending as a patch
|
||||||
|
diffs.append(common.Difference(tf, sf))
|
||||||
|
else:
|
||||||
|
# Target file data identical to source (may still be renamed)
|
||||||
|
pass
|
||||||
|
|
||||||
|
common.ComputeDifferences(diffs)
|
||||||
|
|
||||||
|
for diff in diffs:
|
||||||
|
tf, sf, d = diff.GetPatch()
|
||||||
|
path = "/".join(tf.name.split("/")[:-1])
|
||||||
|
if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
|
||||||
|
path not in known_paths:
|
||||||
|
# patch is almost as big as the file; don't bother patching
|
||||||
|
# or a patch + rename cannot take place due to the target
|
||||||
|
# directory not existing
|
||||||
|
tf.AddToZip(output_zip)
|
||||||
|
verbatim_targets.append((tf.name, tf.size))
|
||||||
|
if sf.name in renames:
|
||||||
|
del renames[sf.name]
|
||||||
|
AddToKnownPaths(tf.name, known_paths)
|
||||||
|
else:
|
||||||
|
common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
|
||||||
|
patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
|
||||||
|
largest_source_size = max(largest_source_size, sf.size)
|
||||||
|
|
||||||
|
self.largest_source_size = largest_source_size
|
||||||
|
|
||||||
|
def EmitVerification(self, script):
|
||||||
|
so_far = 0
|
||||||
|
for tf, sf, size, patch_sha in self.patch_list:
|
||||||
|
if tf.name != sf.name:
|
||||||
|
script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
|
||||||
|
script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
|
||||||
|
so_far += sf.size
|
||||||
|
return so_far
|
||||||
|
|
||||||
|
def RemoveUnneededFiles(self, script, extras=()):
|
||||||
|
script.DeleteFiles(["/"+i[0] for i in self.verbatim_targets] +
|
||||||
|
["/"+i for i in sorted(self.source_data)
|
||||||
|
if i not in self.target_data and
|
||||||
|
i not in self.renames] +
|
||||||
|
list(extras))
|
||||||
|
|
||||||
|
def TotalPatchSize(self):
|
||||||
|
return sum(i[1].size for i in self.patch_list)
|
||||||
|
|
||||||
|
def EmitPatches(self, script, total_patch_size, so_far):
|
||||||
|
self.deferred_patch_list = deferred_patch_list = []
|
||||||
|
for item in self.patch_list:
|
||||||
|
tf, sf, size, _ = item
|
||||||
|
if tf.name == "system/build.prop":
|
||||||
|
deferred_patch_list.append(item)
|
||||||
|
continue
|
||||||
|
if (sf.name != tf.name):
|
||||||
|
script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
|
||||||
|
script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
|
||||||
|
so_far += tf.size
|
||||||
|
script.SetProgress(so_far / total_patch_size)
|
||||||
|
return so_far
|
||||||
|
|
||||||
|
def EmitDeferredPatches(self, script):
|
||||||
|
for item in self.deferred_patch_list:
|
||||||
|
tf, sf, size, _ = item
|
||||||
|
script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
|
||||||
|
script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
|
||||||
|
|
||||||
|
def EmitRenames(self, script):
|
||||||
|
if len(self.renames) > 0:
|
||||||
|
script.Print("Renaming files...")
|
||||||
|
for src, tgt in self.renames.iteritems():
|
||||||
|
print "Renaming " + src + " to " + tgt.name
|
||||||
|
script.RenameFile(src, tgt.name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
||||||
target_has_recovery_patch = HasRecoveryPatch(target_zip)
|
target_has_recovery_patch = HasRecoveryPatch(target_zip)
|
||||||
source_has_recovery_patch = HasRecoveryPatch(source_zip)
|
source_has_recovery_patch = HasRecoveryPatch(source_zip)
|
||||||
@@ -923,75 +1107,13 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
|||||||
metadata=metadata,
|
metadata=metadata,
|
||||||
info_dict=OPTIONS.info_dict)
|
info_dict=OPTIONS.info_dict)
|
||||||
|
|
||||||
print "Loading target..."
|
system_diff = FileDifference("system", source_zip, target_zip, output_zip)
|
||||||
target_data = LoadSystemFiles(target_zip)
|
|
||||||
print "Loading source..."
|
|
||||||
source_data = LoadSystemFiles(source_zip)
|
|
||||||
|
|
||||||
verbatim_targets = []
|
|
||||||
patch_list = []
|
|
||||||
diffs = []
|
|
||||||
renames = {}
|
|
||||||
known_paths = set()
|
|
||||||
largest_source_size = 0
|
|
||||||
|
|
||||||
matching_file_cache = {}
|
|
||||||
for fn, sf in source_data.items():
|
|
||||||
assert fn == sf.name
|
|
||||||
matching_file_cache["path:" + fn] = sf
|
|
||||||
if fn in target_data.keys():
|
|
||||||
AddToKnownPaths(fn, known_paths)
|
|
||||||
# Only allow eligibility for filename/sha matching
|
|
||||||
# if there isn't a perfect path match.
|
|
||||||
if target_data.get(sf.name) is None:
|
|
||||||
matching_file_cache["file:" + fn.split("/")[-1]] = sf
|
|
||||||
matching_file_cache["sha:" + sf.sha1] = sf
|
|
||||||
|
|
||||||
for fn in sorted(target_data.keys()):
|
|
||||||
tf = target_data[fn]
|
|
||||||
assert fn == tf.name
|
|
||||||
sf = ClosestFileMatch(tf, matching_file_cache, renames)
|
|
||||||
if sf is not None and sf.name != tf.name:
|
|
||||||
print "File has moved from " + sf.name + " to " + tf.name
|
|
||||||
renames[sf.name] = tf
|
|
||||||
|
|
||||||
if sf is None or fn in OPTIONS.require_verbatim:
|
|
||||||
# This file should be included verbatim
|
|
||||||
if fn in OPTIONS.prohibit_verbatim:
|
|
||||||
raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
|
|
||||||
print "send", fn, "verbatim"
|
|
||||||
tf.AddToZip(output_zip)
|
|
||||||
verbatim_targets.append((fn, tf.size))
|
|
||||||
if fn in target_data.keys():
|
|
||||||
AddToKnownPaths(fn, known_paths)
|
|
||||||
elif tf.sha1 != sf.sha1:
|
|
||||||
# File is different; consider sending as a patch
|
|
||||||
diffs.append(common.Difference(tf, sf))
|
|
||||||
else:
|
|
||||||
# Target file data identical to source (may still be renamed)
|
|
||||||
pass
|
|
||||||
|
|
||||||
common.ComputeDifferences(diffs)
|
|
||||||
|
|
||||||
for diff in diffs:
|
|
||||||
tf, sf, d = diff.GetPatch()
|
|
||||||
path = "/".join(tf.name.split("/")[:-1])
|
|
||||||
if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
|
|
||||||
path not in known_paths:
|
|
||||||
# patch is almost as big as the file; don't bother patching
|
|
||||||
# or a patch + rename cannot take place due to the target
|
|
||||||
# directory not existing
|
|
||||||
tf.AddToZip(output_zip)
|
|
||||||
verbatim_targets.append((tf.name, tf.size))
|
|
||||||
if sf.name in renames:
|
|
||||||
del renames[sf.name]
|
|
||||||
AddToKnownPaths(tf.name, known_paths)
|
|
||||||
else:
|
|
||||||
common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
|
|
||||||
patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
|
|
||||||
largest_source_size = max(largest_source_size, sf.size)
|
|
||||||
|
|
||||||
script.Mount("/system")
|
script.Mount("/system")
|
||||||
|
if HasVendorPartition(target_zip):
|
||||||
|
vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
|
||||||
|
script.Mount("/vendor")
|
||||||
|
else:
|
||||||
|
vendor_diff = None
|
||||||
|
|
||||||
target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
|
target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
|
||||||
source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
|
source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
|
||||||
@@ -1075,13 +1197,9 @@ else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
|
|||||||
device_specific.IncrementalOTA_VerifyBegin()
|
device_specific.IncrementalOTA_VerifyBegin()
|
||||||
|
|
||||||
script.ShowProgress(0.1, 0)
|
script.ShowProgress(0.1, 0)
|
||||||
so_far = 0
|
so_far = system_diff.EmitVerification(script)
|
||||||
|
if vendor_diff:
|
||||||
for tf, sf, size, patch_sha in patch_list:
|
so_far += vendor_diff.EmitVerification(script)
|
||||||
if tf.name != sf.name:
|
|
||||||
script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
|
|
||||||
script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
|
|
||||||
so_far += sf.size
|
|
||||||
|
|
||||||
if updating_boot:
|
if updating_boot:
|
||||||
d = common.Difference(target_boot, source_boot)
|
d = common.Difference(target_boot, source_boot)
|
||||||
@@ -1099,8 +1217,12 @@ else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
|
|||||||
target_boot.size, target_boot.sha1))
|
target_boot.size, target_boot.sha1))
|
||||||
so_far += source_boot.size
|
so_far += source_boot.size
|
||||||
|
|
||||||
if patch_list or updating_recovery or updating_boot:
|
size = []
|
||||||
script.CacheFreeSpaceCheck(largest_source_size)
|
if system_diff.patch_list: size.append(system_diff.largest_source_size)
|
||||||
|
if vendor_diff:
|
||||||
|
if vendor_diff.patch_list: size.append(vendor_diff.largest_source_size)
|
||||||
|
if size or updating_recovery or updating_boot:
|
||||||
|
script.CacheFreeSpaceCheck(max(size))
|
||||||
|
|
||||||
device_specific.IncrementalOTA_VerifyEnd()
|
device_specific.IncrementalOTA_VerifyEnd()
|
||||||
|
|
||||||
@@ -1122,30 +1244,22 @@ else
|
|||||||
print "writing full boot image (forced by two-step mode)"
|
print "writing full boot image (forced by two-step mode)"
|
||||||
|
|
||||||
script.Print("Removing unneeded files...")
|
script.Print("Removing unneeded files...")
|
||||||
script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
|
system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
|
||||||
["/"+i for i in sorted(source_data)
|
if vendor_diff:
|
||||||
if i not in target_data and
|
vendor_diff.RemoveUnneededFiles(script)
|
||||||
i not in renames] +
|
|
||||||
["/system/recovery.img"])
|
|
||||||
|
|
||||||
script.ShowProgress(0.8, 0)
|
script.ShowProgress(0.8, 0)
|
||||||
total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
|
total_patch_size = 1.0 + system_diff.TotalPatchSize()
|
||||||
|
if vendor_diff:
|
||||||
|
total_patch_size += vendor_diff.TotalPatchSize()
|
||||||
if updating_boot:
|
if updating_boot:
|
||||||
total_patch_size += target_boot.size
|
total_patch_size += target_boot.size
|
||||||
so_far = 0
|
|
||||||
|
|
||||||
script.Print("Patching system files...")
|
script.Print("Patching system files...")
|
||||||
deferred_patch_list = []
|
so_far = system_diff.EmitPatches(script, total_patch_size, 0)
|
||||||
for item in patch_list:
|
if vendor_diff:
|
||||||
tf, sf, size, _ = item
|
script.Print("Patching vendor files...")
|
||||||
if tf.name == "system/build.prop":
|
so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
|
||||||
deferred_patch_list.append(item)
|
|
||||||
continue
|
|
||||||
if (sf.name != tf.name):
|
|
||||||
script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
|
|
||||||
script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
|
|
||||||
so_far += tf.size
|
|
||||||
script.SetProgress(so_far / total_patch_size)
|
|
||||||
|
|
||||||
if not OPTIONS.two_step:
|
if not OPTIONS.two_step:
|
||||||
if updating_boot:
|
if updating_boot:
|
||||||
@@ -1166,6 +1280,10 @@ else
|
|||||||
else:
|
else:
|
||||||
print "boot image unchanged; skipping."
|
print "boot image unchanged; skipping."
|
||||||
|
|
||||||
|
system_items = ItemSet("system", "META/filesystem_config.txt")
|
||||||
|
if vendor_diff:
|
||||||
|
vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
|
||||||
|
|
||||||
if updating_recovery:
|
if updating_recovery:
|
||||||
# Recovery is generated as a patch using both the boot image
|
# Recovery is generated as a patch using both the boot image
|
||||||
# (which contains the same linux kernel as recovery) and the file
|
# (which contains the same linux kernel as recovery) and the file
|
||||||
@@ -1179,7 +1297,7 @@ else
|
|||||||
if not target_has_recovery_patch:
|
if not target_has_recovery_patch:
|
||||||
def output_sink(fn, data):
|
def output_sink(fn, data):
|
||||||
common.ZipWriteStr(output_zip, "recovery/" + fn, data)
|
common.ZipWriteStr(output_zip, "recovery/" + fn, data)
|
||||||
Item.Get("system/" + fn, dir=False)
|
system_items.Get("system/" + fn, dir=False)
|
||||||
|
|
||||||
common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
|
common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
|
||||||
target_recovery, target_boot)
|
target_recovery, target_boot)
|
||||||
@@ -1191,16 +1309,24 @@ else
|
|||||||
|
|
||||||
script.ShowProgress(0.1, 10)
|
script.ShowProgress(0.1, 10)
|
||||||
|
|
||||||
target_symlinks = CopySystemFiles(target_zip, None)
|
target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
|
||||||
|
if vendor_diff:
|
||||||
|
target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
|
||||||
|
|
||||||
|
temp_script = script.MakeTemporary()
|
||||||
|
system_items.GetMetadata(target_zip)
|
||||||
|
system_items.Get("system").SetPermissions(temp_script)
|
||||||
|
if vendor_diff:
|
||||||
|
vendor_items.GetMetadata(target_zip)
|
||||||
|
vendor_items.Get("vendor").SetPermissions(temp_script)
|
||||||
|
|
||||||
|
# Note that this call will mess up the trees of Items, so make sure
|
||||||
|
# we're done with them.
|
||||||
|
source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
|
||||||
|
if vendor_diff:
|
||||||
|
source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
|
||||||
|
|
||||||
target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
|
target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
|
||||||
temp_script = script.MakeTemporary()
|
|
||||||
Item.GetMetadata(target_zip)
|
|
||||||
Item.Get("system").SetPermissions(temp_script)
|
|
||||||
|
|
||||||
# Note that this call will mess up the tree of Items, so make sure
|
|
||||||
# we're done with it.
|
|
||||||
source_symlinks = CopySystemFiles(source_zip, None)
|
|
||||||
source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
|
source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
|
||||||
|
|
||||||
# Delete all the symlinks in source that aren't in target. This
|
# Delete all the symlinks in source that aren't in target. This
|
||||||
@@ -1212,20 +1338,20 @@ else
|
|||||||
to_delete.append(link)
|
to_delete.append(link)
|
||||||
script.DeleteFiles(to_delete)
|
script.DeleteFiles(to_delete)
|
||||||
|
|
||||||
if verbatim_targets:
|
if system_diff.verbatim_targets:
|
||||||
script.Print("Unpacking new files...")
|
script.Print("Unpacking new system files...")
|
||||||
script.UnpackPackageDir("system", "/system")
|
script.UnpackPackageDir("system", "/system")
|
||||||
|
if vendor_diff and vendor_diff.verbatim_targets:
|
||||||
|
script.Print("Unpacking new vendor files...")
|
||||||
|
script.UnpackPackageDir("vendor", "/vendor")
|
||||||
|
|
||||||
if updating_recovery and not target_has_recovery_patch:
|
if updating_recovery and not target_has_recovery_patch:
|
||||||
script.Print("Unpacking new recovery...")
|
script.Print("Unpacking new recovery...")
|
||||||
script.UnpackPackageDir("recovery", "/system")
|
script.UnpackPackageDir("recovery", "/system")
|
||||||
|
|
||||||
if len(renames) > 0:
|
system_diff.EmitRenames(script)
|
||||||
script.Print("Renaming files...")
|
if vendor_diff:
|
||||||
|
vendor_diff.EmitRenames(script)
|
||||||
for src in renames:
|
|
||||||
print "Renaming " + src + " to " + renames[src].name
|
|
||||||
script.RenameFile(src, renames[src].name)
|
|
||||||
|
|
||||||
script.Print("Symlinks and permissions...")
|
script.Print("Symlinks and permissions...")
|
||||||
|
|
||||||
@@ -1256,10 +1382,7 @@ else
|
|||||||
# device can still come up, it appears to be the old build and will
|
# device can still come up, it appears to be the old build and will
|
||||||
# get set the OTA package again to retry.
|
# get set the OTA package again to retry.
|
||||||
script.Print("Patching remaining system files...")
|
script.Print("Patching remaining system files...")
|
||||||
for item in deferred_patch_list:
|
system_diff.EmitDeferredPatches(script)
|
||||||
tf, sf, size, _ = item
|
|
||||||
script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
|
|
||||||
script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
|
|
||||||
|
|
||||||
if OPTIONS.wipe_user_data:
|
if OPTIONS.wipe_user_data:
|
||||||
script.Print("Erasing user data...")
|
script.Print("Erasing user data...")
|
||||||
|
Reference in New Issue
Block a user