From patchwork Mon Feb 4 22:31:13 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Terceiro X-Patchwork-Id: 14545 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 0EE9924195 for ; Mon, 4 Feb 2013 22:31:20 +0000 (UTC) Received: from mail-ve0-f172.google.com (mail-ve0-f172.google.com [209.85.128.172]) by fiordland.canonical.com (Postfix) with ESMTP id 65D8BA19610 for ; Mon, 4 Feb 2013 22:31:19 +0000 (UTC) Received: by mail-ve0-f172.google.com with SMTP id cz11so3730827veb.17 for ; Mon, 04 Feb 2013 14:31:18 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:content-type:mime-version:x-launchpad-project :x-launchpad-branch:x-launchpad-message-rationale :x-launchpad-branch-revision-number:x-launchpad-notification-type:to :from:subject:message-id:date:reply-to:sender:errors-to:precedence :x-generated-by:x-launchpad-hash:x-gm-message-state; bh=ia0xrTktHY5GRxJrhO0PL0x6r0U/ClZvKa03r4ElBsU=; b=RtESEdEIPoMPJFqS7LrOpJPfv6JSrNPntu5spcT444UznP3SeEUHkpNLadZttdu2y5 g0R+c8kcN40ll1pPqqFCw03LqTr6p0RLn+DUqQEspwNIDd0HzaHELysXKDEH1bKIk2jO fal/srtXDuyFuP3TSdxqUSMP84txs/+ikVoXh27PAOfA79Yn0sHbKM6YOwhUPu++rP8v wBZ+nKcnNzJrNoR1N38jZK1zqjtdDJadAirWBX23+TfadKYdR9KJx0Neu9T2c6w616GB It/R2wwFqlho240TYy9BCzxosjIREX8imEoiPiEuqR7MN29JrrSYNcwOxgKVn61P99vH ++cQ== X-Received: by 10.52.21.146 with SMTP id v18mr21445167vde.79.1360017078720; Mon, 04 Feb 2013 14:31:18 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.58.252.8 with SMTP id zo8csp110013vec; Mon, 4 Feb 2013 14:31:16 -0800 (PST) X-Received: by 10.180.94.234 with SMTP id df10mr13239990wib.17.1360017076250; Mon, 04 Feb 2013 14:31:16 -0800 (PST) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id s2si1479822wja.15.2013.02.04.14.31.14 (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 04 Feb 2013 14:31:16 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1U2UZF-0007Le-Oh for ; Mon, 04 Feb 2013 22:31:13 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id 9798FE02C7 for ; Mon, 4 Feb 2013 22:31:13 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: lava-dispatcher X-Launchpad-Branch: ~linaro-validation/lava-dispatcher/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 552 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~linaro-validation/lava-dispatcher/trunk] Rev 552: Guard fastboot invocations from concurrent execution Message-Id: <20130204223113.5903.10537.launchpad@ackee.canonical.com> Date: Mon, 04 Feb 2013 22:31:13 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="16468"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: 0fab2630d59681df4bfe60149ea138005597acda X-Gm-Message-State: ALoCoQmntfvtkIGbXSzgb1nZELgOBrPlkn36Cdkqm57Yxsdbz0wwLY9UROFgvE4HtcBn1CJm88SY Merge authors: Antonio Terceiro (terceiro) Related merge proposals: https://code.launchpad.net/~terceiro/lava-dispatcher/fastboot-flock/+merge/146251 proposed by: Antonio Terceiro (terceiro) ------------------------------------------------------------ revno: 552 [merge] committer: Antonio Terceiro branch nick: trunk timestamp: Mon 2013-02-04 19:30:00 -0300 message: Guard fastboot invocations from concurrent execution modified: lava_dispatcher/device/nexus.py --- lp:lava-dispatcher https://code.launchpad.net/~linaro-validation/lava-dispatcher/trunk You are subscribed to branch lp:lava-dispatcher. To unsubscribe from this branch go to https://code.launchpad.net/~linaro-validation/lava-dispatcher/trunk/+edit-subscription === modified file 'lava_dispatcher/device/nexus.py' --- lava_dispatcher/device/nexus.py 2013-01-22 01:45:32 +0000 +++ lava_dispatcher/device/nexus.py 2013-02-04 13:31:34 +0000 @@ -39,6 +39,67 @@ CriticalError ) + +def _call(cmd, ignore_failure, timeout): + cmd = 'timeout ' + str(timeout) + 's ' + cmd + logging.debug("Running on the host: %s", cmd) + if ignore_failure: + subprocess.call(cmd, shell=True) + else: + subprocess.check_call(cmd, shell=True) + + +class FastBoot(object): + + def __init__(self, device): + self.device = device + + def __call__(self, args, ignore_failure=False, timeout=600): + command = self.device.config.fastboot_command + ' ' + args + command = "flock /var/lock/lava-fastboot.lck " + command + _call(command, ignore_failure, timeout) + + def enter(self): + if self.on(): + logging.debug("Device is on fastboot - no need to hard reset") + return + try: + # First we try a gentle reset + self.device._adb('reboot') + except subprocess.CalledProcessError: + # Now a more brute force attempt. In this case the device is + # probably hung. + if self.device.config.hard_reset_command: + logging.debug("Will hard reset the device") + logging_system(self.device.config.hard_reset_command) + else: + logging.critical( + "Hard reset command not configured. " + "Please reset the device manually." + ) + + def on(self): + try: + self('getvar all', timeout=2) + return True + except subprocess.CalledProcessError: + return False + + def erase(self, partition): + self('erase %s' % partition) + + def flash(self, partition, image): + self('flash %s %s' % (partition, image)) + + def boot(self, image): + # We need an extra bootloader reboot before actually booting the image + # to avoid the phone entering charging mode and getting stuck. + self('reboot') + # specifically after `fastboot reset`, we have to wait a little + sleep(10) + self('boot %s' % image) + + class NexusTarget(Target): def __init__(self, context, config): @@ -52,6 +113,7 @@ self._booted = False self._working_dir = None + self.fastboot = FastBoot(self) def deploy_android(self, boot, system, userdata): @@ -59,10 +121,10 @@ system = self._get_image(system) userdata = self._get_image(userdata) - self._enter_fastboot() - self._fastboot('erase boot') - self._fastboot('flash system %s' % system) - self._fastboot('flash userdata %s' % userdata) + self.fastboot.enter() + self.fastboot.erase('boot') + self.fastboot.flash('system', system) + self.fastboot.flash('userdata', userdata) self.deployment_data = Target.android_deployment_data self.deployment_data['boot_image'] = boot @@ -71,11 +133,12 @@ if not self.deployment_data.get('boot_image', False): raise CriticalError('Deploy action must be run first') - self._enter_fastboot() - self._boot_test_image() + self.fastboot.enter() + self.fastboot.boot(self.deployment_data['boot_image']) + self._adb('wait-for-device') self._booted = True - proc = self._adb('shell', spawn = True) + proc = self._adb('shell', spawn=True) proc.sendline("") # required to put the adb shell in a reasonable state proc.sendline("export PS1='%s'" % self.deployment_data['TESTER_PS1']) self._runner = self._get_runner(proc) @@ -98,7 +161,7 @@ target_dir = '%s/%s' % (mount_point, directory) subprocess.check_call(['mkdir', '-p', host_dir]) - self._adb('pull %s %s' % (target_dir, host_dir), ignore_failure = True) + self._adb('pull %s %s' % (target_dir, host_dir), ignore_failure=True) yield host_dir @@ -109,46 +172,11 @@ # number. For now let's use just the adb version number. return subprocess.check_output( "%s version | sed 's/.* version //'" % self.config.adb_command, - shell = True + shell=True ).strip() # start of private methods - def _enter_fastboot(self): - if self._already_on_fastboot(): - logging.debug("Device is on fastboot - no need to hard reset") - return - try: - # First we try a gentle reset - self._adb('reboot') - except subprocess.CalledProcessError: - # Now a more brute force attempt. In this case the device is - # probably hung. - if self.config.hard_reset_command: - logging.debug("Will hard reset the device") - logging_system(self.config.hard_reset_command) - else: - logging.critical( - "Hard reset command not configured. " - "Please reset the device manually." - ) - - def _already_on_fastboot(self): - try: - self._fastboot('getvar all', timeout = 2) - return True - except subprocess.CalledProcessError: - return False - - def _boot_test_image(self): - # We need an extra bootloader reboot before actually booting the image - # to avoid the phone entering charging mode and getting stuck. - self._fastboot('reboot') - # specifically after `fastboot reset`, we have to wait a little - sleep(10) - self._fastboot('boot %s' % self.deployment_data['boot_image']) - self._adb('wait-for-device') - def _get_partition_mount_point(self, partition): lookup = { self.config.data_part_android_org: '/data', @@ -156,23 +184,12 @@ } return lookup[partition] - def _adb(self, args, ignore_failure = False, spawn = False, timeout = 600): + def _adb(self, args, ignore_failure=False, spawn=False, timeout=600): cmd = self.config.adb_command + ' ' + args if spawn: - return logging_spawn(cmd, timeout = 60) - else: - self._call(cmd, ignore_failure, timeout) - - def _fastboot(self, args, ignore_failure = False, timeout = 600): - self._call(self.config.fastboot_command + ' ' + args, ignore_failure, timeout) - - def _call(self, cmd, ignore_failure, timeout): - cmd = 'timeout ' + str(timeout) + 's ' + cmd - logging.debug("Running on the host: %s" % cmd) - if ignore_failure: - subprocess.call(cmd, shell = True) - else: - subprocess.check_call(cmd, shell = True) + return logging_spawn(cmd, timeout=60) + else: + _call(cmd, ignore_failure, timeout) def _get_image(self, url): sdir = self.working_dir