File: android.py

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (170 lines) | stat: -rw-r--r-- 5,317 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import os
import logging
import posixpath
import time

from contextlib import contextmanager
from typing import List, Optional

import attr

from chrome.test.variations.drivers import DriverFactory
# This import also adds `devil` and `build/android` to `sys.path`.
from chrome.test.variations.test_utils import android
from selenium import webdriver

from devil.android import device_temp_file
from devil.android import device_utils
from devil.android.sdk import intent

# Wait time after loading a page to allow the scrollbar to disappear before
# taking a screenshot.
SCREENSHOT_WAIT_TIME_SECONDS = 5

@attr.attrs()
class AndroidDriverFactory(DriverFactory):
  channel: str = attr.attrib()
  avd_config: Optional[str] = attr.attrib()
  enabled_emulator_window: bool = attr.attrib()
  ports: List[int] = attr.attrib()

  #override
  def __attrs_post_init__(self):
    super().__attrs_post_init__()
    self._instance = android.launch_emulator(
      avd_config=self.avd_config,
      emulator_window=self.enabled_emulator_window,
      ports=self.ports)
    self._device_temp_dir = device_temp_file.NamedDeviceTemporaryDirectory(
      self.device.adb)
    self._install_package()

  def _install_package(self):
    self._package_name = android.install_chrome(self.channel, self.device)
    self.device.ClearApplicationState(self.package_name)
    logging.info('Installed Chrome (%s)', self.package_name)

  #override
  @property
  def supports_startup_timeout(self) -> bool:
    # Android doesn't support browser startup timeout.
    return False

  @property
  def device_temp_dir(self) -> device_temp_file.NamedDeviceTemporaryDirectory:
    return self._device_temp_dir

  @property
  def package_name(self) -> str:
    return self._package_name

  @property
  def activity_name(self) -> Optional[str]:
    return None

  @property
  def device(self) -> device_utils.DeviceUtils:
    return self._instance.device

  def _push_seed(self, seed_file: str):
    local_seed_file = posixpath.join(
      self.device_temp_dir.name, os.path.basename(seed_file))
    self.device.adb.Push(seed_file, local_seed_file)

    uid = self.device.GetUidForPackage(self.package_name)
    self.device.RunShellCommand(
      ['chown', uid, local_seed_file], as_root=True)
    return local_seed_file

  #override
  def wait_for_screenshot(self):
    time.sleep(SCREENSHOT_WAIT_TIME_SECONDS)

  #override
  @contextmanager
  def create_driver(
    self,
    seed_file: Optional[str] = None,
    options: Optional[webdriver.ChromeOptions] = None
    ) -> webdriver.Remote:
    options = options or self.default_options
    options.enable_mobile(
      android_package=self.package_name,
      android_activity=self.activity_name,
    )
    # We clean up the application dir and place several files there, so
    # we need to keep the data when running webdriver.
    options.mobile_options['androidKeepAppDataDir'] = True

    if seed_file:
      installed_seed_path = self._push_seed(seed_file)
      logging.info('Installed seed at (%s)', installed_seed_path)
      options.add_argument(
        f'variations-test-seed-path={installed_seed_path}')
      options.add_argument(f'--fake-variations-channel={self.channel}')
      # TODO(http://crbug.com/379869158) -- remove this once the new
      # seed loading mechanism is fixed.
      options.add_argument(
        '--force-fieldtrials=SeedFileTrial/Default')

    driver = None
    try:
      yield (driver := webdriver.Chrome(service=self.get_driver_service(),
                                        options=options))
    finally:
      if driver:
        driver.quit()

  #override
  def close(self):
    self._instance.Stop()


@attr.attrs()
class WebviewDriverFactory(AndroidDriverFactory):

  #override
  @property
  def package_name(self):
    return 'org.chromium.webview_shell'

  #override
  @property
  def activity_name(self):
    return '.WebViewBrowserActivity'

  #override
  def _install_package(self):
    # Clear the system webview shell.
    self.device.ClearApplicationState(self.package_name)

    ver = android.install_webview(self.channel, self.device)
    logging.info('Installed webview (%s)', ver)

    # Launch shell once to create local state files.
    self.device.StartActivity(
        intent.Intent(
            action='android.intent.action.MAIN',
            package=self.package_name,
            activity='.WebViewBrowserActivity'),
        blocking=True)
    self.device.ForceStop(self.package_name)

  #override
  def _push_seed(self, seed_file: str):
    # Variation seeds for webview are always being loaded from app_webview.
    package_dir = self.device.GetApplicationDataDirectory(self.package_name)
    app_data_dir = posixpath.join(package_dir, 'app_webview')
    local_seed_file = super()._push_seed(seed_file)

    seed_path = posixpath.join(app_data_dir, 'variations_seed')
    seed_new_path = posixpath.join(app_data_dir, 'variations_seed_new')
    self.device.RunShellCommand(
      ['cp', local_seed_file, seed_path], check_return=True, as_root=True)
    self.device.RunShellCommand(
      ['cp', local_seed_file, seed_new_path], check_return=True, as_root=True)
    return local_seed_file