普通文本  |  175行  |  7.35 KB

# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging

import pm_errors
import state_machine

from autotest_lib.client.cros.cellular import mm1_constants

class DisableMachine(state_machine.StateMachine):
    """
    DisableMachine handles the state transitions involved in bringing the modem
    to the DISABLED state.

    """
    def __init__(self, modem, return_cb, raise_cb):
        super(DisableMachine, self).__init__(modem)
        self.return_cb = return_cb
        self.raise_cb = raise_cb


    def _HandleConnectedState(self):
        logging.info('DisableMachine: Modem is CONNECTED.')
        assert self._modem.connect_step is None
        # TODO(armansito): Pass a different raise_cb here to handle
        # disconnect failure
        logging.info('DisableMachine: Starting Disconnect.')
        self._modem.Disconnect(mm1_constants.ROOT_PATH, DisableMachine.Step,
                               DisableMachine.Step, self)
        return True


    def _HandleConnectingState(self):
        logging.info('DisableMachine: Modem is CONNECTING.')
        assert self._modem.connect_step
        logging.info('DisableMachine: Canceling connect.')
        self._modem.connect_step.Cancel()
        return True


    def _HandleDisconnectingState(self):
        logging.info('DisableMachine: Modem is DISCONNECTING.')
        assert self._modem.disconnect_step
        logging.info('DisableMachine: Waiting for disconnect.')
        # wait until disconnect ends
        return True


    def _HandleRegisteredState(self):
        logging.info('DisableMachine: Modem is REGISTERED.')
        assert not self._modem.IsPendingRegister()
        assert not self._modem.IsPendingEnable()
        assert not self._modem.IsPendingConnect()
        assert not self._modem.IsPendingDisconnect()
        self._modem.UnregisterWithNetwork()
        logging.info('DisableMachine: Setting state to DISABLING.')
        reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
        self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLING, reason)
        return True


    def _HandleSearchingState(self):
        logging.info('DisableMachine: Modem is SEARCHING.')
        assert self._modem.register_step
        assert not self._modem.IsPendingEnable()
        assert not self._modem.IsPendingConnect()
        logging.info('DisableMachine: Canceling register.')
        self._modem.register_step.Cancel()
        return True


    def _HandleEnabledState(self):
        logging.info('DisableMachine: Modem is ENABLED.')
        assert not self._modem.IsPendingRegister()
        assert not self._modem.IsPendingEnable()
        assert not self._modem.IsPendingConnect()
        logging.info('DisableMachine: Setting state to DISABLING.')
        reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
        self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLING, reason)
        return True


    def _HandleDisablingState(self):
        logging.info('DisableMachine: Modem is DISABLING.')
        assert not self._modem.IsPendingRegister()
        assert not self._modem.IsPendingEnable()
        assert not self._modem.IsPendingConnect()
        assert not self._modem.IsPendingDisconnect()
        logging.info('DisableMachine: Setting state to DISABLED.')
        reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
        self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLED, reason)
        self._modem.disable_step = None
        if self.return_cb:
            self.return_cb()
        return False


    def _GetModemStateFunctionMap(self):
        return {
            mm1_constants.MM_MODEM_STATE_CONNECTED:
                    DisableMachine._HandleConnectedState,
            mm1_constants.MM_MODEM_STATE_CONNECTING:
                    DisableMachine._HandleConnectingState,
            mm1_constants.MM_MODEM_STATE_DISCONNECTING:
                    DisableMachine._HandleDisconnectingState,
            mm1_constants.MM_MODEM_STATE_REGISTERED:
                    DisableMachine._HandleRegisteredState,
            mm1_constants.MM_MODEM_STATE_SEARCHING:
                    DisableMachine._HandleSearchingState,
            mm1_constants.MM_MODEM_STATE_ENABLED:
                    DisableMachine._HandleEnabledState,
            mm1_constants.MM_MODEM_STATE_DISABLING:
                    DisableMachine._HandleDisablingState
        }


    def _ShouldStartStateMachine(self):
        if self._modem.disable_step and self._modem.disable_step != self:
            # There is already a disable operation in progress.
            message = 'Modem disable already in progress.'
            logging.info(message)
            raise pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS,
                                        message)
        elif self._modem.disable_step is None:
            # There is no disable operation going in, cancelled or otherwise.
            state = self._modem.Get(mm1_constants.I_MODEM, 'State')
            if state == mm1_constants.MM_MODEM_STATE_DISABLED:
                # The reason we're not raising an error here is that
                # shill will make multiple successive calls to disable
                # but WON'T check for raised errors, which causes
                # problems. Treat this particular case as success.
                logging.info('Already in a disabled state. Ignoring.')
                if self.return_cb:
                    self.return_cb()
                return False

            invalid_states = [
                mm1_constants.MM_MODEM_STATE_FAILED,
                mm1_constants.MM_MODEM_STATE_UNKNOWN,
                mm1_constants.MM_MODEM_STATE_INITIALIZING,
                mm1_constants.MM_MODEM_STATE_LOCKED
            ]
            if state in invalid_states:
                raise pm_errors.MMCoreError(
                        pm_errors.MMCoreError.WRONG_STATE,
                        ('Modem disable cannot be initiated while in state'
                         ' %u.') % state)
            if self._modem.connect_step:
                logging.info('There is an ongoing Connect, canceling it.')
                self._modem.connect_step.Cancel()
            if self._modem.register_step:
                logging.info('There is an ongoing Register, canceling it.')
                self._modem.register_step.Cancel()
            if self._modem.enable_step:
                # This needs to be done here, because the case where an enable
                # cycle has been initiated but it hasn't triggered any state
                # transitions yet would not be detected in a state handler.
                logging.info('There is an ongoing Enable, canceling it.')
                logging.info('This should bring the modem to a disabled state.'
                             ' DisableMachine will not start.')
                self._modem.enable_step.Cancel()
                assert self._modem.Get(mm1_constants.I_MODEM, 'State') == \
                    mm1_constants.MM_MODEM_STATE_DISABLED
            if self._modem.Get(mm1_constants.I_MODEM, 'State') == \
                    mm1_constants.MM_MODEM_STATE_DISABLED:
                if self.return_cb:
                    self.return_cb()
                return False

            logging.info('Starting Disable.')
            self._modem.disable_step = self
        return True