Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 1 | # Copyright 2018 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | import contextlib |
| 6 | import json |
| 7 | import logging |
| 8 | from lxml import etree |
| 9 | import os |
| 10 | import StringIO |
| 11 | |
| 12 | from autotest_lib.client.common_lib import utils |
Kuo Jen Wei | 377e99b | 2020-02-25 16:39:42 +0800 | [diff] [blame] | 13 | from autotest_lib.server.cros.tradefed import tradefed_chromelogin as login |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 14 | |
| 15 | |
| 16 | class ChartFixture: |
| 17 | """Sets up chart tablet to display dummy scene image.""" |
| 18 | DISPLAY_SCRIPT = '/usr/local/autotest/bin/display_chart.py' |
| 19 | |
| 20 | def __init__(self, chart_host, scene_uri): |
| 21 | self.host = chart_host |
| 22 | self.scene_uri = scene_uri |
| 23 | self.display_pid = None |
| 24 | |
| 25 | def initialize(self): |
| 26 | """Prepare scene file and display it on chart host.""" |
| 27 | logging.info('Prepare scene file') |
| 28 | chart_dir = self.host.get_tmp_dir() |
| 29 | scene_path = os.path.join( |
| 30 | chart_dir, self.scene_uri[self.scene_uri.rfind('/') + 1:]) |
| 31 | self.host.run('wget', args=('-O', scene_path, self.scene_uri)) |
| 32 | self.host.run('chmod', args=('-R', '755', chart_dir)) |
| 33 | |
| 34 | logging.info('Display scene file') |
| 35 | self.display_pid = self.host.run_background( |
Kuo Jen Wei | 377e99b | 2020-02-25 16:39:42 +0800 | [diff] [blame] | 36 | 'python2 %s %s' % (self.DISPLAY_SCRIPT, scene_path)) |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 37 | # TODO(inker): Suppose chart should be displayed very soon. Or require |
| 38 | # of waiting until chart actually displayed. |
| 39 | |
| 40 | def cleanup(self): |
| 41 | """Cleanup display script.""" |
| 42 | if self.display_pid is not None: |
| 43 | self.host.run('kill', args=('-2', str(self.display_pid))) |
| 44 | |
| 45 | |
| 46 | def get_chart_address(host_address, args): |
Kuo Jen Wei | 3e89c44 | 2019-01-29 14:27:26 +0800 | [diff] [blame] | 47 | """Get address of chart tablet from commandline args or mapping logic in |
| 48 | test lab. |
| 49 | |
| 50 | @param host_address: a list of hostname strings. |
| 51 | @param args: a dict parse from commandline args. |
| 52 | @return: |
| 53 | A list of strings for chart tablet addresses. |
| 54 | """ |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 55 | address = utils.args_to_dict(args).get('chart') |
| 56 | if address is not None: |
| 57 | return address.split(',') |
| 58 | elif utils.is_in_container(): |
Kuo Jen Wei | 377e99b | 2020-02-25 16:39:42 +0800 | [diff] [blame] | 59 | return [utils.get_lab_chart_address(host) for host in host_address] |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 60 | else: |
| 61 | return None |
| 62 | |
| 63 | |
| 64 | class DUTFixture: |
| 65 | """Sets up camera filter for target camera facing on DUT.""" |
| 66 | TEST_CONFIG_PATH = '/var/cache/camera/test_config.json' |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 67 | CAMERA_PROFILE_PATH = ('/mnt/stateful_partition/encrypted/var/cache/camera' |
| 68 | '/media_profiles.xml') |
| 69 | |
| 70 | def __init__(self, test, host, facing): |
| 71 | self.test = test |
| 72 | self.host = host |
| 73 | self.facing = facing |
| 74 | |
| 75 | @contextlib.contextmanager |
| 76 | def _set_selinux_permissive(self): |
| 77 | selinux_mode = self.host.run_output('getenforce') |
| 78 | self.host.run('setenforce 0') |
| 79 | yield |
| 80 | self.host.run('setenforce', args=(selinux_mode, )) |
| 81 | |
| 82 | def _filter_camera_profile(self, content, facing): |
| 83 | """Filter camera profile of target facing from content of camera |
| 84 | profile. |
| 85 | |
| 86 | @return: |
| 87 | New camera profile with only target facing, camera ids are |
| 88 | renumbered from 0. |
| 89 | """ |
| 90 | tree = etree.parse( |
| 91 | StringIO.StringIO(content), |
| 92 | parser=etree.XMLParser(compact=False)) |
| 93 | root = tree.getroot() |
| 94 | profiles = root.findall('CamcorderProfiles') |
| 95 | logging.debug('%d number of camera(s) found in camera profile', |
| 96 | len(profiles)) |
| 97 | assert 1 <= len(profiles) <= 2 |
| 98 | if len(profiles) == 2: |
| 99 | cam_id = 0 if facing == 'back' else 1 |
| 100 | for p in profiles: |
| 101 | if cam_id == int(p.attrib['cameraId']): |
| 102 | p.attrib['cameraId'] = '0' |
| 103 | else: |
| 104 | root.remove(p) |
| 105 | else: |
Kuo Jen Wei | 377e99b | 2020-02-25 16:39:42 +0800 | [diff] [blame] | 106 | with login.login_chrome( |
| 107 | hosts=[self.host], |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 108 | board=self.test._get_board_name(), |
Kuo Jen Wei | 377e99b | 2020-02-25 16:39:42 +0800 | [diff] [blame] | 109 | ), self._set_selinux_permissive(): |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 110 | has_front_camera = ( |
| 111 | 'feature:android.hardware.camera.front' in self.host. |
| 112 | run_output('android-sh -c "pm list features"')) |
| 113 | logging.debug('has_front_camera=%s', has_front_camera) |
| 114 | if (facing == 'front') != has_front_camera: |
| 115 | root.remove(profiles[0]) |
| 116 | return etree.tostring( |
| 117 | tree, xml_declaration=True, encoding=tree.docinfo.encoding) |
| 118 | |
| 119 | def _read_file(self, filepath): |
| 120 | """Read content of filepath from host.""" |
| 121 | tmp_path = os.path.join(self.test.tmpdir, os.path.basename(filepath)) |
| 122 | self.host.get_file(filepath, tmp_path, delete_dest=True) |
| 123 | with open(tmp_path) as f: |
| 124 | return f.read() |
| 125 | |
| 126 | def _write_file(self, filepath, content, permission=None, owner=None): |
| 127 | """Write content to filepath on remote host. |
| 128 | @param permission: set permission to 0xxx octal number of remote file. |
| 129 | @param owner: set owner of remote file. |
| 130 | """ |
| 131 | tmp_path = os.path.join(self.test.tmpdir, os.path.basename(filepath)) |
| 132 | with open(tmp_path, 'w') as f: |
| 133 | f.write(content) |
| 134 | if permission is not None: |
| 135 | os.chmod(tmp_path, permission) |
| 136 | self.host.send_file(tmp_path, filepath, delete_dest=True) |
| 137 | if owner is not None: |
| 138 | self.host.run('chown', args=(owner, filepath)) |
| 139 | |
| 140 | def initialize(self): |
| 141 | """Filter out camera other than target facing on DUT.""" |
| 142 | logging.info('Restart camera service with filter option') |
| 143 | self._write_file( |
| 144 | self.TEST_CONFIG_PATH, |
| 145 | json.dumps({ |
| 146 | 'enable_back_camera': self.facing == 'back', |
| 147 | 'enable_front_camera': self.facing == 'front', |
| 148 | 'enable_external_camera': False |
| 149 | }), |
| 150 | owner='arc-camera') |
| 151 | self.host.run('restart cros-camera') |
| 152 | |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 153 | logging.info('Replace camera profile in ARC++ container') |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 154 | profile = self._read_file(self.CAMERA_PROFILE_PATH) |
| 155 | new_profile = self._filter_camera_profile(profile, self.facing) |
| 156 | self._write_file(self.CAMERA_PROFILE_PATH, new_profile) |
| 157 | self.host.run('restart ui') |
| 158 | |
| 159 | def cleanup(self): |
| 160 | """Cleanup camera filter.""" |
| 161 | logging.info('Remove filter option and restore camera service') |
| 162 | self.host.run('rm', args=('-f', self.TEST_CONFIG_PATH)) |
| 163 | self.host.run('restart cros-camera') |
| 164 | |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 165 | logging.info('Restore camera profile in ARC++ container') |
Kuo Jen Wei | 7f00bb3 | 2018-11-01 15:35:24 +0800 | [diff] [blame] | 166 | self.host.run('restart ui') |