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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') | 129 self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator') |
130 self.popen = None | 130 self.popen = None |
131 self.device = None | 131 self.device = None |
132 self.fast_and_loose = fast_and_loose | 132 self.fast_and_loose = fast_and_loose |
133 | 133 |
134 def _DeviceName(self): | 134 def _DeviceName(self): |
135 """Return our device name.""" | 135 """Return our device name.""" |
136 port = _GetAvailablePort() | 136 port = _GetAvailablePort() |
137 return ('emulator-%d' % port, port) | 137 return ('emulator-%d' % port, port) |
138 | 138 |
139 def Launch(self): | 139 def Launch(self, kill_all_emulators): |
140 """Launches the emulator and waits for package manager to startup. | 140 """Launches the emulator asynchronously. Call ConfirmLaunch() to ensure the |
| 141 emulator is ready for use. |
141 | 142 |
142 If fails, an exception will be raised. | 143 If fails, an exception will be raised. |
143 """ | 144 """ |
144 _KillAllEmulators() # just to be sure | 145 if kill_all_emulators: |
| 146 _KillAllEmulators() # just to be sure |
145 if not self.fast_and_loose: | 147 if not self.fast_and_loose: |
146 self._AggressiveImageCleanup() | 148 self._AggressiveImageCleanup() |
147 (self.device, port) = self._DeviceName() | 149 (self.device, port) = self._DeviceName() |
148 emulator_command = [ | 150 emulator_command = [ |
149 self.emulator, | 151 self.emulator, |
150 # Speed up emulator launch by 40%. Really. | 152 # Speed up emulator launch by 40%. Really. |
151 '-no-boot-anim', | 153 '-no-boot-anim', |
152 # The default /data size is 64M. | 154 # The default /data size is 64M. |
153 # That's not enough for 4 unit test bundles and their data. | 155 # That's not enough for 4 unit test bundles and their data. |
154 '-partition-size', '256', | 156 '-partition-size', '256', |
155 # Use a familiar name and port. | 157 # Use a familiar name and port. |
156 '-avd', 'buildbot', | 158 '-avd', 'buildbot', |
157 '-port', str(port)] | 159 '-port', str(port)] |
158 if not self.fast_and_loose: | 160 if not self.fast_and_loose: |
159 emulator_command.extend([ | 161 emulator_command.extend([ |
160 # Wipe the data. We've seen cases where an emulator | 162 # Wipe the data. We've seen cases where an emulator |
161 # gets 'stuck' if we don't do this (every thousand runs or | 163 # gets 'stuck' if we don't do this (every thousand runs or |
162 # so). | 164 # so). |
163 '-wipe-data', | 165 '-wipe-data', |
164 ]) | 166 ]) |
165 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) | 167 logging.info('Emulator launch command: %s', ' '.join(emulator_command)) |
166 self.popen = subprocess.Popen(args=emulator_command, | 168 self.popen = subprocess.Popen(args=emulator_command, |
167 stderr=subprocess.STDOUT) | 169 stderr=subprocess.STDOUT) |
168 self._InstallKillHandler() | 170 self._InstallKillHandler() |
169 self._ConfirmLaunch() | |
170 | 171 |
171 def _AggressiveImageCleanup(self): | 172 def _AggressiveImageCleanup(self): |
172 """Aggressive cleanup of emulator images. | 173 """Aggressive cleanup of emulator images. |
173 | 174 |
174 Experimentally it looks like our current emulator use on the bot | 175 Experimentally it looks like our current emulator use on the bot |
175 leaves image files around in /tmp/android-$USER. If a "random" | 176 leaves image files around in /tmp/android-$USER. If a "random" |
176 name gets reused, we choke with a 'File exists' error. | 177 name gets reused, we choke with a 'File exists' error. |
177 TODO(jrg): is there a less hacky way to accomplish the same goal? | 178 TODO(jrg): is there a less hacky way to accomplish the same goal? |
178 """ | 179 """ |
179 logging.info('Aggressive Image Cleanup') | 180 logging.info('Aggressive Image Cleanup') |
180 emulator_imagedir = '/tmp/android-%s' % os.environ['USER'] | 181 emulator_imagedir = '/tmp/android-%s' % os.environ['USER'] |
181 if not os.path.exists(emulator_imagedir): | 182 if not os.path.exists(emulator_imagedir): |
182 return | 183 return |
183 for image in os.listdir(emulator_imagedir): | 184 for image in os.listdir(emulator_imagedir): |
184 full_name = os.path.join(emulator_imagedir, image) | 185 full_name = os.path.join(emulator_imagedir, image) |
185 if 'emulator' in full_name: | 186 if 'emulator' in full_name: |
186 logging.info('Deleting emulator image %s', full_name) | 187 logging.info('Deleting emulator image %s', full_name) |
187 os.unlink(full_name) | 188 os.unlink(full_name) |
188 | 189 |
189 def _ConfirmLaunch(self, wait_for_boot=False): | 190 def ConfirmLaunch(self, wait_for_boot=False): |
190 """Confirm the emulator launched properly. | 191 """Confirm the emulator launched properly. |
191 | 192 |
192 Loop on a wait-for-device with a very small timeout. On each | 193 Loop on a wait-for-device with a very small timeout. On each |
193 timeout, check the emulator process is still alive. | 194 timeout, check the emulator process is still alive. |
194 After confirming a wait-for-device can be successful, make sure | 195 After confirming a wait-for-device can be successful, make sure |
195 it returns the right answer. | 196 it returns the right answer. |
196 """ | 197 """ |
197 a = android_commands.AndroidCommands(self.device, False) | 198 a = android_commands.AndroidCommands(self.device, False) |
198 seconds_waited = 0 | 199 seconds_waited = 0 |
199 number_of_waits = 2 # Make sure we can wfd twice | 200 number_of_waits = 2 # Make sure we can wfd twice |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 """Install a handler to kill the emulator when we exit unexpectedly.""" | 245 """Install a handler to kill the emulator when we exit unexpectedly.""" |
245 for sig in self._SIGNALS: | 246 for sig in self._SIGNALS: |
246 signal.signal(sig, self._ShutdownOnSignal) | 247 signal.signal(sig, self._ShutdownOnSignal) |
247 | 248 |
248 def main(argv): | 249 def main(argv): |
249 Emulator().launch() | 250 Emulator().launch() |
250 | 251 |
251 | 252 |
252 if __name__ == '__main__': | 253 if __name__ == '__main__': |
253 main(sys.argv) | 254 main(sys.argv) |
OLD | NEW |