blob: 1523f1f41fcdd6b4294e5f5286534dd4263bc080 [file] [log] [blame]
Kuo Jen Wei7f00bb32018-11-01 15:35:24 +08001# 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
5import contextlib
6import json
7import logging
8from lxml import etree
9import os
10import StringIO
11
12from autotest_lib.client.common_lib import utils
13
14
15class ChartFixture:
16 """Sets up chart tablet to display dummy scene image."""
17 DISPLAY_SCRIPT = '/usr/local/autotest/bin/display_chart.py'
18
19 def __init__(self, chart_host, scene_uri):
20 self.host = chart_host
21 self.scene_uri = scene_uri
22 self.display_pid = None
23
24 def initialize(self):
25 """Prepare scene file and display it on chart host."""
26 logging.info('Prepare scene file')
27 chart_dir = self.host.get_tmp_dir()
28 scene_path = os.path.join(
29 chart_dir, self.scene_uri[self.scene_uri.rfind('/') + 1:])
30 self.host.run('wget', args=('-O', scene_path, self.scene_uri))
31 self.host.run('chmod', args=('-R', '755', chart_dir))
32
33 logging.info('Display scene file')
34 self.display_pid = self.host.run_background(
35 'python %s %s' % (self.DISPLAY_SCRIPT, scene_path))
36 # TODO(inker): Suppose chart should be displayed very soon. Or require
37 # of waiting until chart actually displayed.
38
39 def cleanup(self):
40 """Cleanup display script."""
41 if self.display_pid is not None:
42 self.host.run('kill', args=('-2', str(self.display_pid)))
43
44
45def get_chart_address(host_address, args):
46 address = utils.args_to_dict(args).get('chart')
47 if address is not None:
48 return address.split(',')
49 elif utils.is_in_container():
50 return [
51 utils.get_lab_chart_address(host.hostname)
52 for host in host_address
53 ]
54 else:
55 return None
56
57
58class DUTFixture:
59 """Sets up camera filter for target camera facing on DUT."""
60 TEST_CONFIG_PATH = '/var/cache/camera/test_config.json'
61 GENERATE_CAMERA_PROFILE = os.path.join('/usr', 'bin',
62 'generate_camera_profile')
63 GENERATE_CAMERA_PROFILE_BACKUP = GENERATE_CAMERA_PROFILE + '.bak'
64 CAMERA_PROFILE_PATH = ('/mnt/stateful_partition/encrypted/var/cache/camera'
65 '/media_profiles.xml')
66
67 def __init__(self, test, host, facing):
68 self.test = test
69 self.host = host
70 self.facing = facing
71
72 @contextlib.contextmanager
73 def _set_selinux_permissive(self):
74 selinux_mode = self.host.run_output('getenforce')
75 self.host.run('setenforce 0')
76 yield
77 self.host.run('setenforce', args=(selinux_mode, ))
78
79 def _filter_camera_profile(self, content, facing):
80 """Filter camera profile of target facing from content of camera
81 profile.
82
83 @return:
84 New camera profile with only target facing, camera ids are
85 renumbered from 0.
86 """
87 tree = etree.parse(
88 StringIO.StringIO(content),
89 parser=etree.XMLParser(compact=False))
90 root = tree.getroot()
91 profiles = root.findall('CamcorderProfiles')
92 logging.debug('%d number of camera(s) found in camera profile',
93 len(profiles))
94 assert 1 <= len(profiles) <= 2
95 if len(profiles) == 2:
96 cam_id = 0 if facing == 'back' else 1
97 for p in profiles:
98 if cam_id == int(p.attrib['cameraId']):
99 p.attrib['cameraId'] = '0'
100 else:
101 root.remove(p)
102 else:
103 with self.test._login_chrome(
104 board=self.test._get_board_name(),
105 reboot=False), self._set_selinux_permissive():
106 has_front_camera = (
107 'feature:android.hardware.camera.front' in self.host.
108 run_output('android-sh -c "pm list features"'))
109 logging.debug('has_front_camera=%s', has_front_camera)
110 if (facing == 'front') != has_front_camera:
111 root.remove(profiles[0])
112 return etree.tostring(
113 tree, xml_declaration=True, encoding=tree.docinfo.encoding)
114
115 def _read_file(self, filepath):
116 """Read content of filepath from host."""
117 tmp_path = os.path.join(self.test.tmpdir, os.path.basename(filepath))
118 self.host.get_file(filepath, tmp_path, delete_dest=True)
119 with open(tmp_path) as f:
120 return f.read()
121
122 def _write_file(self, filepath, content, permission=None, owner=None):
123 """Write content to filepath on remote host.
124 @param permission: set permission to 0xxx octal number of remote file.
125 @param owner: set owner of remote file.
126 """
127 tmp_path = os.path.join(self.test.tmpdir, os.path.basename(filepath))
128 with open(tmp_path, 'w') as f:
129 f.write(content)
130 if permission is not None:
131 os.chmod(tmp_path, permission)
132 self.host.send_file(tmp_path, filepath, delete_dest=True)
133 if owner is not None:
134 self.host.run('chown', args=(owner, filepath))
135
136 def initialize(self):
137 """Filter out camera other than target facing on DUT."""
138 logging.info('Restart camera service with filter option')
139 self._write_file(
140 self.TEST_CONFIG_PATH,
141 json.dumps({
142 'enable_back_camera': self.facing == 'back',
143 'enable_front_camera': self.facing == 'front',
144 'enable_external_camera': False
145 }),
146 owner='arc-camera')
147 self.host.run('restart cros-camera')
148
149 # To replace camera profile in ARC++ container, arc_setup will run
150 # GENERATE_CAMERA_PROFILE and mount its generated profile under
151 # CAMERA_PROFILE_PATH into container.
152 logging.info('Replace camera profile in ARC++ container')
153 self.host.run(
154 'mv',
155 args=(self.GENERATE_CAMERA_PROFILE,
156 self.GENERATE_CAMERA_PROFILE_BACKUP))
157 self._write_file(
158 self.GENERATE_CAMERA_PROFILE,
159 '''\
160#!/bin/bash
161# Put this executable file to %r to make sure arc-setup knows
162# we're using dynamic media_profiles.xml copy from host path
163# %r''' % (self.GENERATE_CAMERA_PROFILE, self.CAMERA_PROFILE_PATH),
164 permission=0755)
165 profile = self._read_file(self.CAMERA_PROFILE_PATH)
166 new_profile = self._filter_camera_profile(profile, self.facing)
167 self._write_file(self.CAMERA_PROFILE_PATH, new_profile)
168 self.host.run('restart ui')
169
170 def cleanup(self):
171 """Cleanup camera filter."""
172 logging.info('Remove filter option and restore camera service')
173 self.host.run('rm', args=('-f', self.TEST_CONFIG_PATH))
174 self.host.run('restart cros-camera')
175
176 # Restore GENERATE_CAMERA_PROFILE to regenerate camera profile on DUT.
177 logging.info('Restore camera profile in ARC++ container')
178 self.host.run(
179 'mv',
180 args=(self.GENERATE_CAMERA_PROFILE_BACKUP,
181 self.GENERATE_CAMERA_PROFILE),
182 ignore_status=True)
183 self.host.run('restart ui')