def _check_remote_command(self, destination, timeout_ms, success_msgs=None): """Open a stream to destination, check for remote errors. Used for reboot, remount, and root services. If this method returns, the command was successful, otherwise an appropriate error will have been raised. Args: destination: Stream destination to open. timeout_ms: Timeout in milliseconds for the operation. success_msgs: If provided, a list of messages that, if returned from the device, indicate success, so don't treat them as errors. Raises: AdbRemoteError: If the remote command fails, will contain any message we got back from the device. AdbStreamUnavailableError: The service requested isn't supported. """ timeout = timeouts.PolledTimeout.from_millis(timeout_ms) stream = self._adb_connection.open_stream(destination, timeout) if not stream: raise usb_exceptions.AdbStreamUnavailableError( 'Service %s not supported', destination) try: message = stream.read(timeout_ms=timeout) # Some commands report success messages, ignore them. if any([m in message for m in success_msgs]): return except usb_exceptions.CommonUsbError: if destination.startswith('reboot:'): # We expect this if the device is rebooting. return raise raise usb_exceptions.AdbRemoteError('Device message: %s', message)
def read_message(self, timeout=None): """Read a message from this transport and return it. Reads a message of RECV_MSG_TYPE and returns it. Note that this method abstracts the data length and data read so that the caller simply gets the data along with the header in the returned message. Args: timeout: timeouts.PolledTimeout to use for the operation. Returns: An instance of self.RECV_MSG_TYPE that was read from self.stream. Raises: AdbProtocolError: If an invalid response is received. AdbRemoteError: If a FAIL response is received. """ raw_data = self.stream.read( struct.calcsize(self.RECV_MSG_TYPE.struct_format), timeout) try: raw_message = struct.unpack(self.RECV_MSG_TYPE.struct_format, raw_data) except struct.error: raise usb_exceptions.AdbProtocolError( '%s expected format "%s", got data %s' % (self, self.RECV_MSG_TYPE.struct_format, raw_data)) if raw_message[0] not in self.WIRE_TO_CMD: raise usb_exceptions.AdbProtocolError( 'Unrecognized command id: %s' % raw_message) # Swap out the wire command with the string equivalent. raw_message = (self.WIRE_TO_CMD[raw_message[0]], ) + raw_message[1:] if self.RECV_MSG_TYPE.has_data and raw_message[-1]: # For messages that have data, the length of the data is the last field # in the struct. We do another read and swap out that length for the # actual data read before we create the namedtuple to return. data_len = raw_message[-1] raw_message = raw_message[:-1] + (self.stream.read( data_len, timeout), ) if raw_message[0] not in self.VALID_RESPONSES: raise usb_exceptions.AdbProtocolError( '%s not a valid response for %s' % (raw_message[0], self)) if raw_message[0] == 'FAIL': raise usb_exceptions.AdbRemoteError('Remote ADB failure: %s' % raw_message) return self.RECV_MSG_TYPE(*raw_message)