blob: 1ff85a17e6df6b740bbae7721886af0c387dfe54 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Crome OS Configuration access library.
Provides build-time access to the master configuration on the host. It is used
for reading from the master configuration. Consider using cros_config_host.py
for CLI access to this library.
"""
from __future__ import print_function
from collections import OrderedDict
import copy
import json
import os
import sys
# pylint: disable=wrong-import-position
this_dir = os.path.dirname(__file__)
sys.path.insert(0, this_dir)
from cros_config_schema import TransformConfig
from cros_config_schema import GetValidSchemaProperties
from libcros_config_host_base import BaseFile, CrosConfigBaseImpl, DeviceConfig
from libcros_config_host_base import FirmwareInfo, SymlinkedFile
from libcros_config_host_base import FirmwareImage, DeviceSignerInfo
sys.path.pop(0)
UNIBOARD_JSON_INSTALL_PATH = 'usr/share/chromeos-config/config.json'
class DeviceConfigJson(DeviceConfig):
"""JSON specific impl of DeviceConfig
Attributes:
_config: Root dictionary element for a given config.
"""
def __init__(self, config):
self._schema_properties = GetValidSchemaProperties()
self._config = config
self.firmware_info = OrderedDict()
def GetName(self):
return str(self._config['name'])
def GetProperties(self, path):
result = self._config
if path != '/':
for path_token in path[1:].split('/'): # Burn the first '/' char
if path_token in result:
result = result[path_token]
else:
return {}
return result
def GetProperty(self, path, name):
schema_props = self._schema_properties.get(path, None)
if not schema_props or not name in schema_props:
raise Exception('Property not present in schema: %s:%s' % (path, name))
props = self.GetProperties(path)
if props and name in props:
return str(props[name])
return ''
def GetValue(self, source, name):
return source.get(name, None)
def _GetFiles(self, path):
result = []
file_region = self.GetProperties(path)
if file_region and 'files' in file_region:
for item in file_region['files']:
if 'build-path' in item:
result.append(BaseFile(item['build-path'], item['system-path']))
else:
result.append(BaseFile(item['source'], item['destination']))
return result
def _GetSymlinkedFiles(self, path):
result = []
items = self.GetProperties(path)
if items and 'files' in items:
for item in items['files']:
result.append(
SymlinkedFile(item['source'], item['destination'], item['symlink']))
return result
def _GetSystemFileV2(self, path):
return self._GetSystemFilesV2([path])
def _GetSystemFilesV2(self, paths):
result = []
for path in paths:
config = self.GetProperties(path)
if config:
result.append(BaseFile(config['build-path'], config['system-path']))
return result
def GetFirmwareConfig(self):
firmware = self.GetProperties('/firmware')
if not firmware or self.GetValue(firmware, 'no-firmware'):
return {}
return firmware
def GetFirmwareInfo(self):
return self.firmware_info
def GetTouchFirmwareFiles(self):
return self._GetSymlinkedFiles('/touch')
def GetDetachableBaseFirmwareFiles(self):
return self._GetSymlinkedFiles('/detachable-base')
def GetArcFiles(self):
return self._GetSystemFilesV2([
'/arc/hardware-features',
'/arc/media-profiles'])
def GetAudioFiles(self):
return self._GetFiles('/audio/main')
def GetBluetoothFiles(self):
return self._GetSystemFileV2('/bluetooth/config')
def GetCameraFiles(self):
return self._GetSystemFileV2('/camera/config-file')
def GetThermalFiles(self):
return self._GetFiles('/thermal')
def GetIntelWifiSarFiles(self):
return self._GetSystemFileV2('/wifi/sar-file')
def GetWallpaperFiles(self):
result = set()
wallpaper = self.GetValue(self._config, 'wallpaper')
if wallpaper:
result.add(wallpaper)
return result
def GetAutobrightnessFiles(self):
return self._GetSystemFileV2('/power/autobrightness/config-file')
class CrosConfigJson(CrosConfigBaseImpl):
"""JSON specific impl of CrosConfig
Attributes:
_json: Root json for the entire config.
_configs: List of DeviceConfigJson instances
"""
def __init__(self, infile, model_filter_regex=None):
"""Constructor for JSON specific implementation of CrosConfig
Args:
infile: File-like object with JSON configuration
model_filter_regex: Only returns configs that match the filter.
"""
self._json = json.loads(
TransformConfig(infile.read(), model_filter_regex=model_filter_regex))
self._configs = []
for config in self._json['chromeos']['configs']:
self._configs.append(DeviceConfigJson(config))
sorted(self._configs, key=lambda x: str(x.GetProperties('/identity')))
# TODO(shapiroc): This is mess and needs considerable rework on the fw
# side to cleanup, but for now, we're sticking with it in order to
# finish migration to YAML.
fw_by_model = {}
processed = set()
for config in self._configs:
fw = config.GetFirmwareConfig()
# For partial configs (public vs private), we need to support the name
# for cases where identity isn't specified.
identity = config.GetName() + str(config.GetProperties('/identity'))
brand_code = config.GetProperty('/', 'brand-code')
if fw and identity not in processed:
fw_str = str(fw)
shared_model = None
if fw_str not in fw_by_model:
# Use the explict name of the firmware, else use the device name
# This supports equivalence testing with DT since it allowed
# naming firmware images.
fw_by_model[fw_str] = fw.get('name', config.GetName())
shared_model = fw_by_model[fw_str]
build_config = config.GetProperties('/firmware/build-targets')
if build_config:
bios_build_target = config.GetValue(build_config, 'coreboot')
ec_build_target = config.GetValue(build_config, 'ec')
else:
bios_build_target, ec_build_target = None, None
main_image_uri = config.GetValue(fw, 'main-ro-image') or ''
main_rw_image_uri = config.GetValue(fw, 'main-rw-image') or ''
ec_image_uri = config.GetValue(fw, 'ec-ro-image') or ''
pd_image_uri = config.GetValue(fw, 'pd-ro-image') or ''
fw_signer_config = config.GetProperties('/firmware-signing')
key_id = config.GetValue(fw_signer_config, 'key-id')
sig_in_customization_id = config.GetValue(fw_signer_config,
'sig-id-in-customization-id')
have_image = True
name = config.GetName()
if sig_in_customization_id:
sig_id = 'sig-id-in-customization-id'
brand_code = ''
else:
sig_id = config.GetValue(fw_signer_config, 'signature-id')
processed.add(identity)
info = FirmwareInfo(name, shared_model, key_id, have_image,
bios_build_target, ec_build_target, main_image_uri,
main_rw_image_uri, ec_image_uri, pd_image_uri,
sig_id, brand_code)
config.firmware_info[name] = info
if sig_in_customization_id:
for wl_config in self._configs:
if wl_config.GetName() == name:
wl_brand_code = wl_config.GetProperty('/', 'brand-code')
wl_identity_str = str(wl_config.GetProperties('/identity'))
wl_identity = wl_config.GetName() + wl_identity_str
processed.add(wl_identity)
fw_signer_config = wl_config.GetProperties('/firmware-signing')
wl_key_id = wl_config.GetValue(fw_signer_config, 'key-id')
wl_sig_id = wl_config.GetValue(fw_signer_config, 'signature-id')
wl_fw_info = copy.deepcopy(info)
# Firmware info associated with model name should be kept with
# have_image=True so following process will generate one firmware
# entry for this model.
if wl_sig_id == name:
wl_config.firmware_info[wl_sig_id] = wl_fw_info._replace(
brand_code=wl_brand_code)
else:
wl_config.firmware_info[wl_sig_id] = wl_fw_info._replace(
model=wl_sig_id,
key_id=wl_key_id,
have_image=False,
sig_id=wl_sig_id,
brand_code=wl_brand_code)
def GetDeviceConfigs(self):
return self._configs
def GetFirmwareConfigs(self):
result = dict()
for value in self.GetFirmwareInfo().values():
fw_images = []
ap_build_target = value.bios_build_target
ec_build_target = value.ec_build_target
if value.main_image_uri:
fw_images.append(
FirmwareImage(
type='ap',
build_target=ap_build_target,
image_uri=value.main_image_uri))
if value.main_rw_image_uri:
fw_images.append(
FirmwareImage(
type='rw',
build_target=ap_build_target,
image_uri=value.main_rw_image_uri))
if value.ec_image_uri:
fw_images.append(
FirmwareImage(
type='ec',
build_target=ec_build_target,
image_uri=value.ec_image_uri))
if value.pd_image_uri:
fw_images.append(
FirmwareImage(
type='pd',
build_target=ec_build_target,
image_uri=value.pd_image_uri))
result[value.shared_model] = fw_images
return result
def GetFirmwareConfigsByDevice(self):
return {
value.model: value.shared_model or value.model
for value in self.GetFirmwareInfo().values()
}
def GetDeviceSignerInfo(self):
return {
value.model: DeviceSignerInfo(key_id=value.key_id, sig_id=value.sig_id)
for value in self.GetFirmwareInfo().values()
if value.key_id
}