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