#!/usr/bin/env python
#
# Copyright 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helper tool for 'oem at-write-persistent-digest' fastboot command.
This tool generates and stages the correct input data format, based on the
user-provided inputs, for the 'oem at-write-persistent-digest' fastboot command
for Android Things devices before running the command itself.
The input format is defined elsewhere to be the following:
- Name length: 4 bytes (little-endian)
- Name: 'name length' bytes
- Digest length: 4 bytes (little-endian)
- Digest: 'digest length' bytes
Digest length can be zero, indicating that any existing digest with the given
name should be deleted. This corresponds to the '--clear_digest' option for this
tool.
Digest names must be prefixed with 'avb.persistent_digest.', and if the
user-provided name does not include that prefix it is added automatically.
"""
import sys
ver = sys.version_info
if (ver[0] < 2) or (ver[0] == 2 and ver[1] < 7) or (ver[0] == 3 and ver[1] < 2):
print('This script requires Python 2.7+ or 3.2+')
sys.exit(1)
import argparse
import os
import shutil
import struct
import subprocess
import tempfile
HELP_DESCRIPTION = """Helper script for 'fastboot oem
at-write-persistent-digest' that generates and stages the required input data
format."""
AVB_PERSISTENT_DIGEST_PREFIX = 'avb.persistent_digest.'
def WritePersistentDigest(name,
digest=None,
clear_digest=False,
serial=None,
verbose=False):
if not name.startswith(AVB_PERSISTENT_DIGEST_PREFIX):
print("Automatically adding '{}' prefix to persistent value name".format(
AVB_PERSISTENT_DIGEST_PREFIX))
name = AVB_PERSISTENT_DIGEST_PREFIX + name
tempdir = tempfile.mkdtemp()
try:
digest_data = os.path.join(tempdir, 'digest_data')
with open(digest_data, 'wb') as out:
out.write(struct.pack('<I', len(name)))
out.write(name)
if clear_digest:
out.write(struct.pack('<I', 0))
else:
digest_bytes = bytearray.fromhex(digest)
out.write(struct.pack('<I', len(digest_bytes)))
out.write(digest_bytes)
def fastboot_cmd(args):
args = ['fastboot'] + (['-s', serial] if serial else []) + args
if verbose:
print('$ ' + ' '.join(args))
try:
out = subprocess.check_output(
args, stderr=subprocess.STDOUT).decode('utf-8')
except subprocess.CalledProcessError as e:
print(e.output.decode('utf-8'))
print("Command '{}' returned non-zero exit status {}".format(
' '.join(e.cmd), e.returncode))
sys.exit(1)
if verbose:
print(out)
fastboot_cmd(['stage', digest_data])
fastboot_cmd(['oem', 'at-write-persistent-digest'])
print("Persistent value '{}' {}".format(
name, 'cleared' if clear_digest else 'written'))
finally:
shutil.rmtree(tempdir)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=HELP_DESCRIPTION)
# Optional arguments
parser.add_argument(
'-v',
'--verbose',
action='store_true',
help='verbose; prints fastboot commands and their output')
parser.add_argument(
'-s',
'--serial',
help=
"specify device to unlock, either by serial or any other valid value for fastboot's -s arg"
)
# Required arguments
parser.add_argument(
'--name',
required=True,
help=
"persistent digest name to write, 'avb.persistent_digest.' prefix will be automatically added if not already present"
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
'--clear_digest',
action='store_true',
help=
'clear any existing persistent digest value, rather than writing a new value'
)
group.add_argument(
'--digest',
help='persistent digest value to write, as a hex encoded string')
# Print help if no args given
args = parser.parse_args(args=None if sys.argv[1:] else ['-h'])
WritePersistentDigest(
name=args.name,
clear_digest=args.clear_digest,
digest=args.digest,
serial=args.serial,
verbose=args.verbose)