OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Provides an interface to start and stop Android emulator. | 6 """Provides an interface to start and stop Android emulator. |
7 | 7 |
8 Assumes system environment ANDROID_NDK_ROOT has been set. | 8 Assumes system environment ANDROID_NDK_ROOT has been set. |
9 | 9 |
10 Emulator: The class provides the methods to launch/shutdown the emulator with | 10 Emulator: The class provides the methods to launch/shutdown the emulator with |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 | 83 |
84 # Time to wait for an emulator launch, in seconds. This includes | 84 # Time to wait for an emulator launch, in seconds. This includes |
85 # the time to launch the emulator and a wait-for-device command. | 85 # the time to launch the emulator and a wait-for-device command. |
86 _LAUNCH_TIMEOUT = 120 | 86 _LAUNCH_TIMEOUT = 120 |
87 | 87 |
88 # Timeout interval of wait-for-device command before bouncing to a a | 88 # Timeout interval of wait-for-device command before bouncing to a a |
89 # process life check. | 89 # process life check. |
90 _WAITFORDEVICE_TIMEOUT = 5 | 90 _WAITFORDEVICE_TIMEOUT = 5 |
91 | 91 |
92 # Time to wait for a "wait for boot complete" (property set on device). | 92 # Time to wait for a "wait for boot complete" (property set on device). |
93 _WAITFORBOOT_TIMEOUT = 120 | 93 _WAITFORBOOT_TIMEOUT = 300 |
94 | 94 |
95 def __init__(self): | 95 def __init__(self): |
96 try: | 96 try: |
97 android_sdk_root = os.environ['ANDROID_SDK_ROOT'] | 97 android_sdk_root = os.environ['ANDROID_SDK_ROOT'] |
98 except KeyError: | 98 except KeyError: |
99 logging.critical('The ANDROID_SDK_ROOT must be set to run the test on ' | 99 logging.critical('The ANDROID_SDK_ROOT must be set to run the test on ' |
100 'emulator.') | 100 'emulator.') |
101 raise | 101 raise |
102 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') | 102 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') |
103 self.popen = None | 103 self.popen = None |
104 self.device = None | 104 self.device = None |
105 | 105 |
106 def _DeviceName(self): | 106 def _DeviceName(self): |
107 """Return our device name.""" | 107 """Return our device name.""" |
108 port = _GetAvailablePort() | 108 port = _GetAvailablePort() |
109 return ('emulator-%d' % port, port) | 109 return ('emulator-%d' % port, port) |
110 | 110 |
111 def Launch(self): | 111 def Launch(self): |
112 """Launches the emulator and waits for package manager to startup. | 112 """Launches the emulator and waits for package manager to startup. |
113 | 113 |
114 If fails, an exception will be raised. | 114 If fails, an exception will be raised. |
115 """ | 115 """ |
116 _KillAllEmulators() # just to be sure | 116 _KillAllEmulators() # just to be sure |
117 (self.device, port) = self._DeviceName() | 117 (self.device, port) = self._DeviceName() |
118 self.popen = subprocess.Popen(args=[ | 118 emulator_command = [ |
119 self.emulator, | 119 self.emulator, |
120 # Speed up emulator launch by 40%. Really. | 120 # Speed up emulator launch by 40%. Really. |
121 '-no-boot-anim', | 121 '-no-boot-anim', |
122 # The default /data size is 64M. | 122 # The default /data size is 64M. |
123 # That's not enough for 4 unit test bundles and their data. | 123 # That's not enough for 4 unit test bundles and their data. |
124 '-partition-size', '256', | 124 '-partition-size', '256', |
125 # ALWAYS wipe the data. We've seen cases where an emulator | |
126 # gets 'stuck' if we don't do this (every thousand runs or | |
127 # so). | |
128 '-wipe-data', | |
125 # Use a familiar name and port. | 129 # Use a familiar name and port. |
126 '-avd', 'buildbot', | 130 '-avd', 'buildbot', |
127 '-port', str(port)], | 131 '-port', str(port)] |
128 stderr=subprocess.STDOUT) | 132 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) |
133 self.popen = subprocess.Popen(args=emulator_command, | |
bulach
2011/12/07 22:55:57
nit: popen is too generic.. perhaps rather than se
John Grabowski
2011/12/07 22:57:31
It returns a popen object.
Class is emulator so I
| |
134 stderr=subprocess.STDOUT) | |
129 self._InstallKillHandler() | 135 self._InstallKillHandler() |
130 self._ConfirmLaunch() | 136 self._ConfirmLaunch() |
131 | 137 |
132 def _ConfirmLaunch(self): | 138 def _ConfirmLaunch(self, wait_for_boot=False): |
133 """Confirm the emulator launched properly. | 139 """Confirm the emulator launched properly. |
134 | 140 |
135 Loop on a wait-for-device with a very small timeout. On each | 141 Loop on a wait-for-device with a very small timeout. On each |
136 timeout, check the emulator process is still alive. | 142 timeout, check the emulator process is still alive. |
137 After confirming a wait-for-device can be successful, make sure | 143 After confirming a wait-for-device can be successful, make sure |
138 it returns the right answer. | 144 it returns the right answer. |
139 """ | 145 """ |
140 a = android_commands.AndroidCommands(self.device, False) | 146 a = android_commands.AndroidCommands(self.device, False) |
141 seconds_waited = 0 | 147 seconds_waited = 0 |
142 number_of_waits = 2 # Make sure we can wfd twice | 148 number_of_waits = 2 # Make sure we can wfd twice |
143 adb_cmd = "adb -s %s %s" % (self.device, 'wait-for-device') | 149 adb_cmd = "adb -s %s %s" % (self.device, 'wait-for-device') |
144 while seconds_waited < self._LAUNCH_TIMEOUT: | 150 while seconds_waited < self._LAUNCH_TIMEOUT: |
145 try: | 151 try: |
146 run_command.RunCommand(adb_cmd, | 152 run_command.RunCommand(adb_cmd, |
147 timeout_time=self._WAITFORDEVICE_TIMEOUT, | 153 timeout_time=self._WAITFORDEVICE_TIMEOUT, |
148 retry_count=1) | 154 retry_count=1) |
149 number_of_waits -= 1 | 155 number_of_waits -= 1 |
150 if not number_of_waits: | 156 if not number_of_waits: |
151 break | 157 break |
152 except errors.WaitForResponseTimedOutError as e: | 158 except errors.WaitForResponseTimedOutError as e: |
153 seconds_waited += self._WAITFORDEVICE_TIMEOUT | 159 seconds_waited += self._WAITFORDEVICE_TIMEOUT |
154 adb_cmd = "adb -s %s %s" % (self.device, 'kill-server') | 160 adb_cmd = "adb -s %s %s" % (self.device, 'kill-server') |
155 run_command.RunCommand(adb_cmd) | 161 run_command.RunCommand(adb_cmd) |
156 self.popen.poll() | 162 self.popen.poll() |
157 if self.popen.returncode != None: | 163 if self.popen.returncode != None: |
158 raise EmulatorLaunchException('EMULATOR DIED') | 164 raise EmulatorLaunchException('EMULATOR DIED') |
159 if seconds_waited >= self._LAUNCH_TIMEOUT: | 165 if seconds_waited >= self._LAUNCH_TIMEOUT: |
160 raise EmulatorLaunchException('TIMEOUT with wait-for-device') | 166 raise EmulatorLaunchException('TIMEOUT with wait-for-device') |
161 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) | 167 logging.info('Seconds waited on wait-for-device: %d', seconds_waited) |
162 # Now that we checked for obvious problems, wait for a boot complete. | 168 if wait_for_boot: |
163 # Waiting for the package manager has been problematic. | 169 # Now that we checked for obvious problems, wait for a boot complete. |
164 a.Adb().SetTargetSerial(self.device) | 170 # Waiting for the package manager is sometimes problematic. |
165 a.Adb().WaitForBootComplete(self._WAITFORBOOT_TIMEOUT) | 171 # TODO(jrg): for reasons I don't understand, sometimes this |
172 # gives an "error: device not found" which is only fixed with an | |
173 # 'adb kill-server' command. Fix. | |
174 a.Adb().SetTargetSerial(self.device) | |
175 a.Adb().WaitForBootComplete(self._WAITFORBOOT_TIMEOUT) | |
166 | 176 |
167 def Shutdown(self): | 177 def Shutdown(self): |
168 """Shuts down the process started by launch.""" | 178 """Shuts down the process started by launch.""" |
169 if self.popen: | 179 if self.popen: |
170 self.popen.poll() | 180 self.popen.poll() |
171 if self.popen.returncode == None: | 181 if self.popen.returncode == None: |
172 self.popen.kill() | 182 self.popen.kill() |
173 self.popen = None | 183 self.popen = None |
174 | 184 |
175 def _ShutdownOnSignal(self, signum, frame): | 185 def _ShutdownOnSignal(self, signum, frame): |
176 logging.critical('emulator _ShutdownOnSignal') | 186 logging.critical('emulator _ShutdownOnSignal') |
177 for sig in self._SIGNALS: | 187 for sig in self._SIGNALS: |
178 signal.signal(sig, signal.SIG_DFL) | 188 signal.signal(sig, signal.SIG_DFL) |
179 self.Shutdown() | 189 self.Shutdown() |
180 raise KeyboardInterrupt # print a stack | 190 raise KeyboardInterrupt # print a stack |
181 | 191 |
182 def _InstallKillHandler(self): | 192 def _InstallKillHandler(self): |
183 """Install a handler to kill the emulator when we exit unexpectedly.""" | 193 """Install a handler to kill the emulator when we exit unexpectedly.""" |
184 for sig in self._SIGNALS: | 194 for sig in self._SIGNALS: |
185 signal.signal(sig, self._ShutdownOnSignal) | 195 signal.signal(sig, self._ShutdownOnSignal) |
186 | 196 |
187 def main(argv): | 197 def main(argv): |
188 Emulator().launch() | 198 Emulator().launch() |
189 | 199 |
190 | 200 |
191 if __name__ == '__main__': | 201 if __name__ == '__main__': |
192 main(sys.argv) | 202 main(sys.argv) |
OLD | NEW |