def UpdateDependency(dependency_name, dependency_info, local_path, platform):
    bucket = dependency_info['cloud_storage_bucket']
    folder = dependency_info['cloud_storage_base_folder']

    # determine the hash
    ec, sha1sum_output = cmd_helper.GetCmdStatusAndOutput(
        ['sha1sum', local_path])
    if ec:
        raise base_error.BaseError('Failed to determine SHA1 for %s: %s' %
                                   (local_path, sha1sum_output))

    dependency_sha1 = sha1sum_output.split()[0]

    # upload
    remote_path = '%s_%s' % (dependency_name, dependency_sha1)
    gs_dest = 'gs://%s/%s/%s' % (bucket, folder, remote_path)
    ec, gsutil_output = cmd_helper.GetCmdStatusAndOutput(
        ['gsutil.py', 'cp', local_path, gs_dest])
    if ec:
        raise base_error.BaseError('Failed to upload %s to %s: %s' %
                                   (remote_path, gs_dest, gsutil_output))

    # update entry in json
    file_info = dependency_info['file_info']
    if platform not in file_info:
        file_info[platform] = {
            'cloud_storage_hash': '',
            # the user will need to manually update the download path after
            # uploading a previously unknown dependency.
            'download_path': 'FIXME',
        }
    file_info[platform]['cloud_storage_hash'] = dependency_sha1
Esempio n. 2
0
def _ParseManifestFromApk(apk_path):
    aapt_output = aapt.Dump('xmltree', apk_path, 'AndroidManifest.xml')

    parsed_manifest = {}
    node_stack = [parsed_manifest]
    indent = '  '

    if aapt_output[0].startswith('N'):
        # if the first line is a namespace then the root manifest is indented, and
        # we need to add a dummy namespace node, then skip the first line (we dont
        # care about namespaces).
        node_stack.insert(0, {})
        output_to_parse = aapt_output[1:]
    else:
        output_to_parse = aapt_output

    for line in output_to_parse:
        if len(line) == 0:
            continue

        # If namespaces are stripped, aapt still outputs the full url to the
        # namespace and appends it to the attribute names.
        line = line.replace('http://schemas.android.com/apk/res/android:',
                            'android:')

        indent_depth = 0
        while line[(len(indent) * indent_depth):].startswith(indent):
            indent_depth += 1

        # Pop the stack until the height of the stack is the same is the depth of
        # the current line within the tree.
        node_stack = node_stack[:indent_depth + 1]
        node = node_stack[-1]

        # Element nodes are a list of python dicts while attributes are just a dict.
        # This is because multiple elements, at the same depth of tree and the same
        # name, are all added to the same list keyed under the element name.
        m = _MANIFEST_ELEMENT_RE.match(line[len(indent) * indent_depth:])
        if m:
            manifest_key = m.group(1)
            if manifest_key in node:
                node[manifest_key] += [{}]
            else:
                node[manifest_key] = [{}]
            node_stack += [node[manifest_key][-1]]
            continue

        m = _MANIFEST_ATTRIBUTE_RE.match(line[len(indent) * indent_depth:])
        if m:
            manifest_key = m.group(1)
            if manifest_key in node:
                raise base_error.BaseError(
                    "A single attribute should have one key and one value")
            else:
                node[manifest_key] = m.group(2) or m.group(3)
            continue

    return parsed_manifest
Esempio n. 3
0
 def GetInstrumentationName(
     self, default='android.test.InstrumentationTestRunner'):
   """Returns the name of the Instrumentation in the apk."""
   all_instrumentations = self.GetAllInstrumentations(default=default)
   if len(all_instrumentations) != 1:
     raise base_error.BaseError(
         'There is more than one instrumentation. Expected one.')
   else:
     return self._ResolveName(all_instrumentations[0]['android:name'])
def UpdateGivenDependency(dependencies, args):
    dep_name = args.name or os.path.basename(args.path)
    if not dep_name in dependencies.get('dependencies', {}):
        raise base_error.BaseError('Could not find dependency "%s" in %s' %
                                   (dep_name, args.dependencies_json))

    UpdateDependency(dep_name,
                     dependencies.get('dependencies', {}).get(dep_name, {}),
                     args.path, args.platform)

    return dependencies
def BuildTargetsForCpu(targets, cpu, output_dir):
    logging.info('Building %s', cpu)

    gn_args = [
        'ffmpeg_branding="Chrome"',
        'is_component_build=false',
        'is_debug=false',
        'proprietary_codecs=true',
        'symbol_level=1',
        'target_cpu="%s"' % cpu,
        'target_os="android"',
        'use_goma=true',
    ]

    cmd = ['gn', 'gen', '--args=%s' % (' '.join(gn_args)), output_dir]
    ec = cmd_helper.RunCmd(cmd)
    if ec:
        raise base_error.BaseError('%s failed with %d' % (cmd, ec))

    ec = cmd_helper.RunCmd(['autoninja', '-C', output_dir] + targets)
    if ec:
        raise base_error.BaseError('building %s failed with %d' % (cpu, ec))
Esempio n. 6
0
def ExtractApks(output_dir,
                apks_path,
                abis,
                locales,
                features,
                pixel_density,
                sdk_version,
                modules=None):
    """Extracts splits from APKS archive.

  Args:
    output_dir: Directory to extract splits into.
    apks_path: Path to APKS archive.
    abis: ABIs to support.
    locales: Locales to support.
    features: Device features to support.
    pixel_density: Pixel density to support.
    sdk_version: Target SDK version.
    modules: Extra modules to install.
  """
    device_spec = {
        'supportedAbis': abis,
        'supportedLocales': ['%s-%s' % l for l in locales],
        'deviceFeatures': features,
        'screenDensity': pixel_density,
        'sdkVersion': sdk_version,
    }
    with tempfile_ext.TemporaryFileName(suffix='.json') as device_spec_path:
        with open(device_spec_path, 'w') as f:
            json.dump(device_spec, f)
        cmd = [
            'java',
            '-jar',
            _bundletool_path.read(),
            'extract-apks',
            '--apks=%s' % apks_path,
            '--device-spec=%s' % device_spec_path,
            '--output-dir=%s' % output_dir,
        ]
        if modules:
            cmd += ['--modules=%s' % ','.join(modules)]
        status, stdout, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd)
        if status != 0:
            raise base_error.BaseError(
                'Failed running {} with output\n{}\n{}'.format(
                    ' '.join(cmd), stdout, stderr))
Esempio n. 7
0
 def GetAbis(self):
   """Returns a list of ABIs in the apk (empty list if no native code)."""
   # Use lib/* to determine the compatible ABIs.
   libs = set()
   for path in self._ListApkPaths():
     path_tokens = path.split('/')
     if len(path_tokens) >= 2 and path_tokens[0] == 'lib':
       libs.add(path_tokens[1])
   lib_to_abi = {
       abis.ARM: [abis.ARM, abis.ARM_64],
       abis.ARM_64: [abis.ARM_64],
       abis.X86: [abis.X86, abis.X86_64],
       abis.X86_64: [abis.X86_64]
   }
   try:
     output = set()
     for lib in libs:
       for abi in lib_to_abi[lib]:
         output.add(abi)
     return sorted(output)
   except KeyError:
     raise base_error.BaseError('Unexpected ABI in lib/* folder.')
Esempio n. 8
0
def _ParseManifestFromApk(apk_path):
    aapt_output = aapt.Dump('xmltree', apk_path, 'AndroidManifest.xml')

    parsed_manifest = {}
    node_stack = [parsed_manifest]
    indent = '  '

    for line in aapt_output[1:]:
        if len(line) == 0:
            continue

        indent_depth = 0
        while line[(len(indent) * indent_depth):].startswith(indent):
            indent_depth += 1

        node_stack = node_stack[:indent_depth]
        node = node_stack[-1]

        m = _MANIFEST_ELEMENT_RE.match(line[len(indent) * indent_depth:])
        if m:
            manifest_key = m.group(1)
            if manifest_key in node:
                node[manifest_key] += [{}]
            else:
                node[manifest_key] = [{}]
            node_stack += [node[manifest_key][-1]]
            continue

        m = _MANIFEST_ATTRIBUTE_RE.match(line[len(indent) * indent_depth:])
        if m:
            manifest_key = m.group(1)
            if manifest_key in node:
                raise base_error.BaseError(
                    "A single attribute should have one key and one value")
            else:
                node[manifest_key] = m.group(2) or m.group(3)
            continue

    return parsed_manifest