• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#
3# Copyright 2018 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""Action to create goldfish device instances.
17
18A Goldfish device is an emulated android device based on the android
19emulator.
20"""
21import logging
22import os
23
24from acloud import errors
25from acloud.public.actions import base_device_factory
26from acloud.public.actions import common_operations
27from acloud.internal import constants
28from acloud.internal.lib import android_build_client
29from acloud.internal.lib import auth
30from acloud.internal.lib import goldfish_compute_client
31from acloud.internal.lib import utils
32
33logger = logging.getLogger(__name__)
34
35_EMULATOR_INFO_FILENAME = "emulator-info.txt"
36_EMULATOR_VERSION_PATTERN = "version-emulator"
37_SYSIMAGE_INFO_FILENAME = "android-info.txt"
38_SYSIMAGE_VERSION_PATTERN = "version-sysimage-{}-{}"
39
40
41class GoldfishDeviceFactory(base_device_factory.BaseDeviceFactory):
42    """A class that can produce a goldfish device.
43
44    Attributes:
45        _cfg: An AcloudConfig instance.
46        _build_target: String, the build target, e.g. aosp_x86-eng.
47        _build_id: String, Build id, e.g. "2263051", "P2804227"
48        _emulator_build_target: String, the emulator build target, e.g. aosp_x86-eng.
49        _emulator_build_id: String, emulator build id.
50        _gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80"
51        _blank_data_disk_size_gb: Integer, extra disk size
52        _build_client: An AndroidBuildClient instance
53        _branch: String, android branch name, e.g. git_master
54        _emulator_branch: String, emulator branch name, e.g. "aosp-emu-master-dev"
55    """
56    LOG_FILES = ["/home/vsoc-01/emulator.log",
57                 "/home/vsoc-01/log/logcat.log",
58                 "/home/vsoc-01/log/adb.log",
59                 "/var/log/daemon.log"]
60
61    def __init__(self,
62                 cfg,
63                 build_target,
64                 build_id,
65                 emulator_build_target,
66                 emulator_build_id,
67                 gpu=None,
68                 avd_spec=None):
69
70        """Initialize.
71
72        Args:
73            cfg: An AcloudConfig instance.
74            build_target: String, the build target, e.g. aosp_x86-eng.
75            build_id: String, Build id, e.g. "2263051", "P2804227"
76            emulator_build_target: String, the emulator build target, e.g. aosp_x86-eng.
77            emulator_build_id: String, emulator build id.
78            gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80"
79            avd_spec: An AVDSpec instance.
80        """
81
82        self.credentials = auth.CreateCredentials(cfg)
83
84        compute_client = goldfish_compute_client.GoldfishComputeClient(
85            cfg, self.credentials)
86        super(GoldfishDeviceFactory, self).__init__(compute_client)
87
88        # Private creation parameters
89        self._cfg = cfg
90        self._build_target = build_target
91        self._build_id = build_id
92        self._emulator_build_id = emulator_build_id
93        self._emulator_build_target = emulator_build_target
94        self._gpu = gpu
95        self._avd_spec = avd_spec
96        self._blank_data_disk_size_gb = cfg.extra_data_disk_size_gb
97        self._extra_scopes = cfg.extra_scopes
98
99        # Configure clients
100        self._build_client = android_build_client.AndroidBuildClient(
101            self.credentials)
102
103        # Discover branches
104        self._branch = self._build_client.GetBranch(build_target, build_id)
105        self._emulator_branch = self._build_client.GetBranch(
106            emulator_build_target, emulator_build_id)
107
108    def CreateInstance(self):
109        """Creates single configured goldfish device.
110
111        Override method from parent class.
112
113        Returns:
114            String, the name of the created instance.
115        """
116        instance = self._compute_client.GenerateInstanceName(
117            build_id=self._build_id, build_target=self._build_target)
118
119        self._compute_client.CreateInstance(
120            instance=instance,
121            image_name=self._cfg.stable_goldfish_host_image_name,
122            image_project=self._cfg.stable_goldfish_host_image_project,
123            build_target=self._build_target,
124            branch=self._branch,
125            build_id=self._build_id,
126            emulator_branch=self._emulator_branch,
127            emulator_build_id=self._emulator_build_id,
128            gpu=self._gpu,
129            blank_data_disk_size_gb=self._blank_data_disk_size_gb,
130            avd_spec=self._avd_spec,
131            extra_scopes=self._extra_scopes)
132
133        return instance
134
135
136def ParseBuildInfo(filename, pattern):
137    """Parse build id based on a substring.
138
139    This will parse a file which contains build information to be used. For an
140    emulator build, the file will contain the information about the corresponding
141    stable system image build id. Similarly, for a system image build, the file
142    will contain the information about the corresponding stable emulator build id.
143    Pattern is a substring being used as a key to parse the build info. For
144    example, "version-sysimage-git_pi-dev-sdk_gphone_x86_64-userdebug".
145
146    Args:
147        filename: Name of file to parse.
148        pattern: Substring to look for in file
149
150    Returns:
151        Build id parsed from the file based on pattern
152        Returns None if pattern not found in file
153    """
154    with open(filename) as build_info_file:
155        for line in build_info_file:
156            if pattern in line:
157                return line.rstrip().split("=")[1]
158    return None
159
160
161def _FetchBuildIdFromFile(cfg, build_target, build_id, pattern, filename):
162    """Parse and fetch build id from a file based on a pattern.
163
164    Verify if one of the system image or emulator binary build id is missing.
165    If found missing, then update according to the resource file.
166
167    Args:
168        cfg: An AcloudConfig instance.
169        build_target: Target name.
170        build_id: Build id, a string, e.g. "2263051", "P2804227"
171        pattern: A string to parse build info file.
172        filename: Name of file containing the build info.
173
174    Returns:
175        A build id or None
176    """
177    build_client = android_build_client.AndroidBuildClient(
178        auth.CreateCredentials(cfg))
179
180    with utils.TempDir() as tempdir:
181        temp_filename = os.path.join(tempdir, filename)
182        build_client.DownloadArtifact(build_target,
183                                      build_id,
184                                      filename,
185                                      temp_filename)
186
187        return ParseBuildInfo(temp_filename, pattern)
188
189
190def CreateDevices(avd_spec=None,
191                  cfg=None,
192                  build_target=None,
193                  build_id=None,
194                  emulator_build_id=None,
195                  gpu=None,
196                  num=1,
197                  serial_log_file=None,
198                  logcat_file=None,
199                  autoconnect=False,
200                  branch=None,
201                  report_internal_ip=False):
202    """Create one or multiple Goldfish devices.
203
204    Args:
205        avd_spec: An AVDSpec instance.
206        cfg: An AcloudConfig instance.
207        build_target: String, the build target, e.g. aosp_x86-eng.
208        build_id: String, Build id, e.g. "2263051", "P2804227"
209        emulator_build_id: String, emulator build id.
210        gpu: String, GPU to attach to the device or None. e.g. "nvidia-tesla-k80"
211        num: Integer, Number of devices to create.
212        serial_log_file: String, A path to a file where serial output should
213                        be saved to.
214        logcat_file: String, A path to a file where logcat logs should be saved.
215        autoconnect: Boolean, Create ssh tunnel(s) and adb connect after device creation.
216        branch: String, Branch name for system image.
217        report_internal_ip: Boolean to report the internal ip instead of
218                            external ip.
219
220    Returns:
221        A Report instance.
222    """
223    if avd_spec:
224        cfg = avd_spec.cfg
225        build_target = avd_spec.remote_image[constants.BUILD_TARGET]
226        build_id = avd_spec.remote_image[constants.BUILD_ID]
227        branch = avd_spec.remote_image[constants.BUILD_BRANCH]
228        num = avd_spec.num
229        emulator_build_id = avd_spec.emulator_build_id
230        gpu = avd_spec.gpu
231        serial_log_file = avd_spec.serial_log_file
232        logcat_file = avd_spec.logcat_file
233        autoconnect = avd_spec.autoconnect
234        report_internal_ip = avd_spec.report_internal_ip
235
236    if emulator_build_id is None:
237        logger.info("emulator_build_id not provided. "
238                    "Try to get %s from build %s/%s.", _EMULATOR_INFO_FILENAME,
239                    build_id, build_target)
240        emulator_build_id = _FetchBuildIdFromFile(cfg,
241                                                  build_target,
242                                                  build_id,
243                                                  _EMULATOR_VERSION_PATTERN,
244                                                  _EMULATOR_INFO_FILENAME)
245
246    if emulator_build_id is None:
247        raise errors.CommandArgError("Emulator build id not found "
248                                     "in %s" % _EMULATOR_INFO_FILENAME)
249
250    if build_id is None:
251        pattern = _SYSIMAGE_VERSION_PATTERN.format(branch, build_target)
252        build_id = _FetchBuildIdFromFile(cfg,
253                                         cfg.emulator_build_target,
254                                         emulator_build_id,
255                                         pattern,
256                                         _SYSIMAGE_INFO_FILENAME)
257
258    if build_id is None:
259        raise errors.CommandArgError("Emulator system image build id not found "
260                                     "in %s" % _SYSIMAGE_INFO_FILENAME)
261    logger.info(
262        "Creating a goldfish device in project %s, build_target: %s, "
263        "build_id: %s, emulator_bid: %s, GPU: %s, num: %s, "
264        "serial_log_file: %s, logcat_file: %s, "
265        "autoconnect: %s", cfg.project, build_target, build_id,
266        emulator_build_id, gpu, num, serial_log_file, logcat_file, autoconnect)
267
268    device_factory = GoldfishDeviceFactory(cfg, build_target, build_id,
269                                           cfg.emulator_build_target,
270                                           emulator_build_id, gpu, avd_spec)
271
272    return common_operations.CreateDevices("create_gf", cfg, device_factory,
273                                           num, constants.TYPE_GF,
274                                           report_internal_ip, autoconnect,
275                                           serial_log_file, logcat_file)
276