-
Notifications
You must be signed in to change notification settings - Fork 358
Fastboot Boot support, Android 9 fix, Fixed PycryptodomeAuthSigner's sign method #152
base: master
Are you sure you want to change the base?
Changes from 10 commits
b2f9730
236f61d
bc7b879
2378dc8
fc28f55
8e2178b
b2bf672
9689e50
e1db3c2
43ee205
4e29501
72a27fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
import logging | ||
import os | ||
import struct | ||
from io import BytesIO, StringIO | ||
|
||
from adb import common | ||
from adb import usb_exceptions | ||
|
@@ -99,9 +100,9 @@ def HandleSimpleResponses( | |
info_cb: Optional callback for text sent from the bootloader. | ||
|
||
Returns: | ||
OKAY packet's message. | ||
OKAY packet's message | ||
""" | ||
greateggsgreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return self._AcceptResponses(b'OKAY', info_cb, timeout_ms=timeout_ms) | ||
return self._AcceptResponses(b'OKAY', info_cb, timeout_ms=timeout_ms)[0] | ||
|
||
def HandleDataSending(self, source_file, source_len, | ||
info_cb=DEFAULT_MESSAGE_CALLBACK, | ||
|
@@ -123,9 +124,9 @@ def HandleDataSending(self, source_file, source_len, | |
FastbootInvalidResponse: Fastboot responded with an unknown packet type. | ||
|
||
Returns: | ||
OKAY packet's message. | ||
Tuple - OKAY packet's message, List of preceding Fastboot Messages | ||
""" | ||
accepted_size = self._AcceptResponses( | ||
accepted_size, _msgs = self._AcceptResponses( | ||
b'DATA', info_cb, timeout_ms=timeout_ms) | ||
|
||
accepted_size = binascii.unhexlify(accepted_size[:8]) | ||
|
@@ -151,24 +152,33 @@ def _AcceptResponses(self, expected_header, info_cb, timeout_ms=None): | |
FastbootInvalidResponse: Fastboot responded with an unknown packet type. | ||
|
||
Returns: | ||
OKAY packet's message. | ||
Tuple - OKAY packet's message, List of preceding Fastboot Messages | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What was this change for? It seems like it just makes it so the INFO messages are now returned as well but could that break people since the return format here is new? To be honest it's not a huge deal since I'd imagine not a ton of people using FastbootProtocol directly but just curious There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I didn't like making this change because of API breakage, but in a few tools I've integrated this with I've found it's useful for callers to have a list of the FastbootMessages that were a part of the response to any SimpleCommands. info_cb is useful for logging, but having a list of messages returned right after a call is made is good for making decisions based on specific returns from a command. 'OKAY' only returns if the command was successfully run, but does not capture if the command itself had issues (ie. fastboot boot may return 'OKAY', ['oem unlocking is not enabled'] ) |
||
""" | ||
|
||
messages = [] | ||
|
||
while True: | ||
response = self.usb.BulkRead(64, timeout_ms=timeout_ms) | ||
header = bytes(response[:4]) | ||
remaining = bytes(response[4:]) | ||
|
||
if header == b'INFO': | ||
info_cb(FastbootMessage(remaining, header)) | ||
fbm = FastbootMessage(remaining, header) | ||
messages.append(fbm) | ||
info_cb(fbm) | ||
elif header in self.FINAL_HEADERS: | ||
if header != expected_header: | ||
raise FastbootStateMismatch( | ||
'Expected %s, got %s', expected_header, header) | ||
if header == b'OKAY': | ||
info_cb(FastbootMessage(remaining, header)) | ||
return remaining | ||
fbm = FastbootMessage(remaining, header) | ||
messages.append(fbm) | ||
info_cb(fbm) | ||
return remaining, messages | ||
elif header == b'FAIL': | ||
info_cb(FastbootMessage(remaining, header)) | ||
fbm = FastbootMessage(remaining, header) | ||
messages.append(fbm) | ||
info_cb(fbm) | ||
raise FastbootRemoteFailure('FAIL: %s', remaining) | ||
else: | ||
raise FastbootInvalidResponse( | ||
|
@@ -188,6 +198,7 @@ def _HandleProgress(self, total, progress_callback): | |
|
||
def _Write(self, data, length, progress_callback=None): | ||
"""Sends the data to the device, tracking progress with the callback.""" | ||
progress = None | ||
if progress_callback: | ||
progress = self._HandleProgress(length, progress_callback) | ||
next(progress) | ||
|
@@ -310,20 +321,24 @@ def Download(self, source_file, source_len=0, | |
Returns: | ||
Response to a download request, normally nothing. | ||
""" | ||
|
||
if isinstance(source_file, str): | ||
source_file_path = str(source_file) | ||
source_len = os.stat(source_file).st_size | ||
source_file = open(source_file) | ||
|
||
with source_file: | ||
if source_len == 0: | ||
# Fall back to storing it all in memory :( | ||
data = source_file.read() | ||
source_file = io.BytesIO(data.encode('utf8')) | ||
source_len = len(data) | ||
with open(source_file_path, 'rb') as fh: | ||
source_file = BytesIO(fh.read()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we still need the data.encode('utf8') or was that a bug in the first place? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By data.encode('utf-8') do you mean the BytesIO creation? The behavior here was improved so that a caller to Download() can either pass in a file-like object directly or a string file path. In the event they pass in a string, we have to convert it into a file like object before it's passed into HandleDataSending(). This statement was previously leaving a file handle open, so we read the contents and put it into BytesIO so that it has file-like properties. If this isn't what you meant then let me know! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see what you're referring too. The diff below shows us running data.encode('utf-8') on the file contents. This was a bug because the images that are Downloaded are almost always binary/outside the utf-8 space and would fail. |
||
|
||
if not source_len: | ||
if isinstance(source_file, StringIO): | ||
source_file.seek(0, os.SEEK_END) | ||
source_len = source_file.tell() | ||
source_file.seek(0) | ||
else: | ||
source_len = len(source_file) | ||
|
||
self._protocol.SendCommand(b'download', b'%08x' % source_len) | ||
return self._protocol.HandleDataSending( | ||
source_file, source_len, info_cb, progress_callback=progress_callback) | ||
self._protocol.SendCommand(b'download', b'%08x' % source_len) | ||
return self._protocol.HandleDataSending( | ||
source_file, source_len, info_cb, progress_callback=progress_callback)[0] | ||
|
||
def Flash(self, partition, timeout_ms=0, info_cb=DEFAULT_MESSAGE_CALLBACK): | ||
"""Flashes the last downloaded file to the given partition. | ||
|
@@ -396,3 +411,17 @@ def Reboot(self, target_mode=b'', timeout_ms=None): | |
def RebootBootloader(self, timeout_ms=None): | ||
"""Reboots into the bootloader, usually equiv to Reboot('bootloader').""" | ||
return self._SimpleCommand(b'reboot-bootloader', timeout_ms=timeout_ms) | ||
|
||
def Boot(self, source_file): | ||
""" | ||
Fastboot boot image by sending image from local file system then issuing the boot command | ||
|
||
:param source_file: | ||
greateggsgreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
:return: | ||
""" | ||
|
||
if not os.path.exists(source_file): | ||
raise ValueError("source_file must exist") | ||
|
||
self.Download(source_file) | ||
self._SimpleCommand(b'boot') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very important for Android 9 due to a change in struct apacket's 'data' field in adb.h