| OLD | NEW |
| 1 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Utility library for running a startup profile on an Android device. | 5 """Utility library for running a startup profile on an Android device. |
| 6 | 6 |
| 7 Sets up a device for cygprofile, disables sandboxing permissions, and sets up | 7 Sets up a device for cygprofile, disables sandboxing permissions, and sets up |
| 8 support for web page replay, device forwarding, and fake certificate authority | 8 support for web page replay, device forwarding, and fake certificate authority |
| 9 to make runs repeatable. | 9 to make runs repeatable. |
| 10 """ | 10 """ |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 def RunCygprofileTests(self): | 211 def RunCygprofileTests(self): |
| 212 """Run the cygprofile unit tests suite on the device. | 212 """Run the cygprofile unit tests suite on the device. |
| 213 | 213 |
| 214 Args: | 214 Args: |
| 215 path_to_tests: The location on the host machine with the compiled | 215 path_to_tests: The location on the host machine with the compiled |
| 216 cygprofile test binary. | 216 cygprofile test binary. |
| 217 Returns: | 217 Returns: |
| 218 The exit code for the tests. | 218 The exit code for the tests. |
| 219 """ | 219 """ |
| 220 device_path = '/data/local/tmp/cygprofile_unittests' | 220 device_path = '/data/local/tmp/cygprofile_unittests' |
| 221 self._device.PushChangedFiles([(self._cygprofile_tests, device_path)]) | 221 self._device.old_interface.PushIfNeeded( |
| 222 try: | 222 self._cygprofile_tests, device_path) |
| 223 self._device.RunShellCommand(device_path, check_return=True) | 223 (exit_code, _) = ( |
| 224 except device_errors.CommandFailedError: | 224 self._device.old_interface.GetShellCommandStatusAndOutput( |
| 225 # TODO(jbudorick): Let the exception propagate up once clients can | 225 command=device_path, log_result=True)) |
| 226 # handle it. | 226 return exit_code |
| 227 logging.exception('Failure while running cygprofile_unittests:') | |
| 228 return 1 | |
| 229 return 0 | |
| 230 | 227 |
| 231 def CollectProfile(self, apk, package_info): | 228 def CollectProfile(self, apk, package_info): |
| 232 """Run a profile and collect the log files. | 229 """Run a profile and collect the log files. |
| 233 | 230 |
| 234 Args: | 231 Args: |
| 235 apk: The location of the chrome apk to profile. | 232 apk: The location of the chrome apk to profile. |
| 236 package_info: A PackageInfo structure describing the chrome apk, | 233 package_info: A PackageInfo structure describing the chrome apk, |
| 237 as from pylib/constants. | 234 as from pylib/constants. |
| 238 Returns: | 235 Returns: |
| 239 A list of cygprofile data files. | 236 A list of cygprofile data files. |
| 240 Raises: | 237 Raises: |
| 241 NoCyglogDataError: No data was found on the device. | 238 NoCyglogDataError: No data was found on the device. |
| 242 """ | 239 """ |
| 243 self._Install(apk) | 240 self._Install(apk, package_info) |
| 241 |
| 244 try: | 242 try: |
| 245 changer = self._SetChromeFlags(package_info) | 243 changer = self._SetChromeFlags(package_info) |
| 246 self._SetUpDeviceFolders() | 244 self._SetUpDeviceFolders() |
| 247 # Start up chrome once with a blank page, just to get the one-off | 245 # Start up chrome once with a blank page, just to get the one-off |
| 248 # activities out of the way such as apk resource extraction and profile | 246 # activities out of the way such as apk resource extraction and profile |
| 249 # creation. | 247 # creation. |
| 250 self._StartChrome(package_info, 'about:blank') | 248 self._StartChrome(package_info, 'about:blank') |
| 251 time.sleep(15) | 249 time.sleep(15) |
| 252 self._KillChrome(package_info) | 250 self._KillChrome(package_info) |
| 253 self._SetUpDeviceFolders() | 251 self._SetUpDeviceFolders() |
| 254 with WprManager(self._WPR_ARCHIVE, self._device, | 252 with WprManager(self._WPR_ARCHIVE, self._device, |
| 255 package_info.cmdline_file): | 253 package_info.cmdline_file): |
| 256 self._StartChrome(package_info, self._TEST_URL) | 254 self._StartChrome(package_info, self._TEST_URL) |
| 257 time.sleep(90) | 255 time.sleep(90) |
| 258 self._KillChrome(package_info) | 256 self._KillChrome(package_info) |
| 259 finally: | 257 finally: |
| 260 self._RestoreChromeFlags(changer) | 258 self._RestoreChromeFlags(changer) |
| 261 | 259 |
| 262 data = self._PullCyglogData() | 260 data = self._PullCyglogData() |
| 263 self._DeleteDeviceData() | 261 self._DeleteDeviceData() |
| 264 return data | 262 return data |
| 265 | 263 |
| 266 def Cleanup(self): | 264 def Cleanup(self): |
| 267 """Delete all local and device files left over from profiling. """ | 265 """Delete all local and device files left over from profiling. """ |
| 268 self._DeleteDeviceData() | 266 self._DeleteDeviceData() |
| 269 self._DeleteHostData() | 267 self._DeleteHostData() |
| 270 | 268 |
| 271 def _Install(self, apk): | 269 def _Install(self, apk, package_info): |
| 272 """Installs Chrome.apk on the device. | 270 """Installs Chrome.apk on the device. |
| 273 Args: | 271 Args: |
| 274 apk: The location of the chrome apk to profile. | 272 apk: The location of the chrome apk to profile. |
| 275 package_info: A PackageInfo structure describing the chrome apk, | 273 package_info: A PackageInfo structure describing the chrome apk, |
| 276 as from pylib/constants. | 274 as from pylib/constants. |
| 277 """ | 275 """ |
| 278 print 'Installing apk...' | 276 print 'Installing apk...' |
| 279 self._device.Install(apk) | 277 self._device.old_interface.ManagedInstall(apk, package_info.package) |
| 280 | 278 |
| 281 def _SetUpDevice(self): | 279 def _SetUpDevice(self): |
| 282 """When profiling, files are output to the disk by every process. This | 280 """When profiling, files are output to the disk by every process. This |
| 283 means running without sandboxing enabled. | 281 means running without sandboxing enabled. |
| 284 """ | 282 """ |
| 285 # We need to have adb root in order to pull cyglog data | 283 # We need to have adb root in order to pull cyglog data |
| 286 try: | 284 try: |
| 287 print 'Enabling root...' | 285 print 'Enabling root...' |
| 288 self._device.EnableRoot() | 286 self._device.EnableRoot() |
| 289 # SELinux need to be in permissive mode, otherwise the process cannot | 287 # SELinux need to be in permissive mode, otherwise the process cannot |
| 290 # write the log files. | 288 # write the log files. |
| 291 print 'Putting SELinux in permissive mode...' | 289 print 'Putting SELinux in permissive mode...' |
| 292 self._device.RunShellCommand(['setenforce' '0'], check_return=True) | 290 self._device.old_interface.RunShellCommand('setenforce 0') |
| 293 except device_errors.CommandFailedError as e: | 291 except device_errors.CommandFailedError as e: |
| 294 # TODO(jbudorick) Handle this exception appropriately once interface | 292 # TODO(jbudorick) Handle this exception appropriately once interface |
| 295 # conversions are finished. | 293 # conversions are finished. |
| 296 logging.error(str(e)) | 294 logging.error(str(e)) |
| 297 | 295 |
| 298 def _SetChromeFlags(self, package_info): | 296 def _SetChromeFlags(self, package_info): |
| 299 print 'Setting Chrome flags...' | 297 print 'Setting Chrome flags...' |
| 300 changer = flag_changer.FlagChanger( | 298 changer = flag_changer.FlagChanger( |
| 301 self._device, package_info.cmdline_file) | 299 self._device, package_info.cmdline_file) |
| 302 changer.AddFlags(['--no-sandbox', '--disable-fre']) | 300 changer.AddFlags(['--no-sandbox', '--disable-fre']) |
| 303 return changer | 301 return changer |
| 304 | 302 |
| 305 def _RestoreChromeFlags(self, changer): | 303 def _RestoreChromeFlags(self, changer): |
| 306 print 'Restoring Chrome flags...' | 304 print 'Restoring Chrome flags...' |
| 307 if changer: | 305 if changer: |
| 308 changer.Restore() | 306 changer.Restore() |
| 309 | 307 |
| 310 def _SetUpDeviceFolders(self): | 308 def _SetUpDeviceFolders(self): |
| 311 """Creates folders on the device to store cyglog data. """ | 309 """Creates folders on the device to store cyglog data. """ |
| 312 print 'Setting up device folders...' | 310 print 'Setting up device folders...' |
| 313 self._DeleteDeviceData() | 311 self._DeleteDeviceData() |
| 314 self._device.RunShellCommand( | 312 self._device.old_interface.RunShellCommand( |
| 315 ['mkdir', '-p', str(self._DEVICE_CYGLOG_DIR)], | 313 'mkdir -p %s' % self._DEVICE_CYGLOG_DIR) |
| 316 check_return=True) | |
| 317 | 314 |
| 318 def _DeleteDeviceData(self): | 315 def _DeleteDeviceData(self): |
| 319 """Clears out cyglog storage locations on the device. """ | 316 """Clears out cyglog storage locations on the device. """ |
| 320 self._device.RunShellCommand( | 317 self._device.old_interface.RunShellCommand( |
| 321 ['rm', '-rf', str(self._DEVICE_CYGLOG_DIR)], | 318 'rm -rf %s' % self._DEVICE_CYGLOG_DIR) |
| 322 check_return=True) | |
| 323 | 319 |
| 324 def _StartChrome(self, package_info, url): | 320 def _StartChrome(self, package_info, url): |
| 325 print 'Launching chrome...' | 321 print 'Launching chrome...' |
| 326 self._device.StartActivity( | 322 self._device.StartActivity( |
| 327 intent.Intent(package=package_info.package, | 323 intent.Intent(package=package_info.package, |
| 328 activity=package_info.activity, | 324 activity=package_info.activity, |
| 329 data=url, | 325 data=url, |
| 330 extras={'create_new_tab' : True}), | 326 extras={'create_new_tab' : True}), |
| 331 blocking=True, force_stop=True) | 327 blocking=True, force_stop=True) |
| 332 | 328 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 344 def _PullCyglogData(self): | 340 def _PullCyglogData(self): |
| 345 """Pull the cyglog data off of the device. | 341 """Pull the cyglog data off of the device. |
| 346 | 342 |
| 347 Returns: | 343 Returns: |
| 348 A list of cyglog data files which were pulled. | 344 A list of cyglog data files which were pulled. |
| 349 Raises: | 345 Raises: |
| 350 NoCyglogDataError: No data was found on the device. | 346 NoCyglogDataError: No data was found on the device. |
| 351 """ | 347 """ |
| 352 print 'Pulling cyglog data...' | 348 print 'Pulling cyglog data...' |
| 353 self._SetUpHostFolders() | 349 self._SetUpHostFolders() |
| 354 self._device.PullFile( | 350 self._device.old_interface.Adb().Pull( |
| 355 self._DEVICE_CYGLOG_DIR, self._host_cyglog_dir) | 351 self._DEVICE_CYGLOG_DIR, self._host_cyglog_dir) |
| 356 files = os.listdir(self._host_cyglog_dir) | 352 files = os.listdir(self._host_cyglog_dir) |
| 357 | 353 |
| 358 if len(files) == 0: | 354 if len(files) == 0: |
| 359 raise NoCyglogDataError('No cyglog data was collected') | 355 raise NoCyglogDataError('No cyglog data was collected') |
| 360 | 356 |
| 361 return [os.path.join(self._host_cyglog_dir, x) for x in files] | 357 return [os.path.join(self._host_cyglog_dir, x) for x in files] |
| OLD | NEW |