-
Notifications
You must be signed in to change notification settings - Fork 363
AdbCommands structure change, Pycryptodome support, python3 fixes #82
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
I signed it! |
CLAs look good, thanks! |
EDIT: merged with master |
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.
It's really hard to review this because you changed the spacing as well as the code, so all I see is a wall of red and then green instead of line-by-line changes. Any chance you can undo the formatting changes? I'm not opposed to them, but I'd prefer them as a separate pull-request
adb/adb_commands.py
Outdated
|
||
conn = self._get_service_connection(b'shell:') | ||
|
||
return self.protocol_handler.InteractiveShellCommand(conn, command=command, strip_command=strip_command, |
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.
Can you bring this under 80 chars easily?
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.
Happy to make these formatting changes so its easier to see the diffs, give me a day or so to revisit it and I'll push up the changes.
I actually have a branch somewhere at home changing this to be a class, that staticmethods-on-a-class approach is definitely one of those "man, what was I thinking..." choices. I'm definitely in favor of fixing that to be a normal object-oriented design. In fact, I think it's necessary for a few things I've been wanting to do, like tracking multiple open connections (you've started that here). |
…a bit more work to do
|
||
signed_token = rsa_key.Sign(str(banner)) | ||
# Do not mangle the banner property here by converting it to a string | ||
signed_token = rsa_key.Sign(banner) |
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.
Before this was sending a mangled banner to the device instead of the true string. Removing the string cast fixed this.
adb/adb_commands.py
Outdated
destination_dir = '/data/local/tmp/' | ||
basename = os.path.basename(apk_path) | ||
destination_path = destination_dir + basename | ||
destination_path = os.path.join(destination_dir, basename) |
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.
Concatenating the string often got the path wrong ('/data/local/tmptest' vs '/data/local/tmp/test'). Using os.path.join to ensure it produces a correct path.
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.
The problem with os.path.join is that if you're on Windows, it'll use \
instead of /
. We can use posixpath
still though:
import posixpath; destination_path = posixpath.join(destination_dir, basename)
source_file = open(source_file, 'rb') | ||
|
||
connection = self.protocol_handler.Open( | ||
with source_file: |
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 a bit cleaner than the current should_close variable solution in master. Allows an external caller to pass any file-like object and ensure its properly closed.
Jamey Hicks <jamey.hicks@gmail.com> | ||
Marc-Antoine Ruel <maruel@chromium.org> | ||
Max Borghino <fmborghino@gmail.com> | ||
Mohammad Abu-Garbeyyeh <github@mohammadag.com> |
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.
Manual merge from master
subparsers, parents, adb_commands.AdbCommands.Remount) | ||
common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Root) | ||
common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.EnableVerity) | ||
common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.DisableVerity) |
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.
Manual merge from master
def PortPathMatcher(cls, port_path): | ||
"""Returns a device matcher for the given port path.""" | ||
if isinstance(port_path, basestring): | ||
if isinstance(port_path, str): |
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.
basestring was removed in Python3. Using str here instead for py2/3 compatibility.
adb/filesync_protocol.py
Outdated
""" | ||
if data: | ||
if not isinstance(data, bytes): | ||
if isinstance(data, str): |
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.
Strings are also bytes in Python3. Using str here instead for py2/3 compatibility then always encoding as bytes.
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.
With this change, unicode in Python won't be encoded and we'll try to send unicode over the wire.
What was wrong with the previous line? We need bytes, so if it's not bytes, we encode using utf8 to get bytes.
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.
Fixed
|
||
from setuptools import setup | ||
|
||
# Figure out if the system already has a supported Crypto library |
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.
Not sure if you'll like this, but I wanted a way to not force M2Crypto to be installed in my environment if I had an alternative crypto library that was supported (pycryptodome). Happy to live with this not making it into master.
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.
nah, but I wonder if there's an OR option in setuptools?
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.
Couldn't find an OR option in setuptools. Most just perform logic like this in the actual setup.py.
self.assertEqual(b''.join(responses).decode('utf8'), | ||
adb_commands.Shell(command)) | ||
|
||
def testUninstall(self): |
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.
Manual merge form master.
@fahhem I've updated all tests as well as Fastboot to conform to the new object model. All tests are passing again. |
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.
Thanks for the hard work! Sorry for the delays, but I hope to get back to this next weekend.
If there's anything you don't want to do, just put a TODO on me to do it instead :)
adb/adb_commands.py
Outdated
# Connection table tracks each open AdbConnection objects per service type | ||
# By default, the only service connections that make sense to hold open is (interactive) shell | ||
self._service_connections = { | ||
b'shell:': None |
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.
falsey contents of this dict don't affect anything, why put anything in it? Also, the comment makes it seems like only interactive shells would be kept open, but that's not true.
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.
Okay, I've read more and it looks like _get_service_connection
is only used by shell:
connections, so the logic in it is repeated. How about adding a cache=False
kwarg to it and using it everywhere self.protocol_handler.Open()
is called?
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 becomes a lot more useful for another branch I'm working on right now for implementing the 'adb forward' functionality. There, we'll need to hold/cache the service connection for our proxy while the TCP connection is open. I'll push that up when we're happy with this service connections implementation
Having a cache param in Open() isn't a bad idea, but since the Protocol Handler (AdbMessage) is basically a static class, it cannot hold state data like our get_service_connections method within AdbCommands.
I could refactor calls to protocol_handler.Open() and make them pass through a CreateServiceConnection() sort of method, with a cache=False parameter. Or, leave it to the individual program functions to handle it on their own (as it is now). Fine with either way, let me know what you think.
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.
I've also updated the comments around self._service_connections so its a bit more clear that any service that needs to be persisted can take advantage of it, not just InteractiveShell. Again, this will be much more clear when the tcp:forward service uses this alongside shell:
adb/adb_commands.py
Outdated
destination_dir = '/data/local/tmp/' | ||
basename = os.path.basename(apk_path) | ||
destination_path = destination_dir + basename | ||
destination_path = os.path.join(destination_dir, basename) |
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.
The problem with os.path.join is that if you're on Windows, it'll use \
instead of /
. We can use posixpath
still though:
import posixpath; destination_path = posixpath.join(destination_dir, basename)
self.handle, destination=b'sync:', timeout_ms=timeout_ms) | ||
self.filesync_handler.Push(connection, source_file, device_filename, | ||
self.filesync_handler.Push(connection, source_file, device_filename, | ||
mtime=int(mtime), progress_callback=progress_callback) |
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.
indentation
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 intentional so that the Push() call is within the 'with source_file' block, since Push() uses source_file
adb/adb_commands.py
Outdated
handle = common.TcpHandle(serial, timeout_ms=default_timeout_ms) | ||
|
||
# If there isnt a handle override (used by tests), build one here | ||
if not kwargs.get('handle', None): |
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.
if 'handle' in kwargs:
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.
Fixed
adb/adb_commands.py
Outdated
DeviceIsAvailable, port_path=port_path, serial=serial, | ||
timeout_ms=default_timeout_ms) | ||
return cls.Connect(handle, **kwargs) | ||
self.handle = kwargs.pop('handle') |
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.
not in the docstring here or for fastboot. Also, if you reorder this a bit, you can combine the if/elifs:
if 'handle' in kwargs:
self.handle = kwargs.pop('handle')
elif serial and b':' in serial:
self.handle = common.TcpHandle(serial, timeout_ms=default_timeout_ms)
else:
self.handle = common.UsbHandle.FindAndOpen(
DeviceIsAvailable, port_path=port_path, serial=serial,
timeout_ms=default_timeout_ms)
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.
Fixed, thanks for the suggestion!
from setuptools import setup | ||
|
||
# Figure out if the system already has a supported Crypto library | ||
rsa_signer_library = 'M2Crypto>=0.21.1,<=0.26.4' |
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 a no-op, set it to None here to avoid the double mention of the version string
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.
Wasn't able to find an 'OR' option in setup tools without writing the logic in. I've removed one of the version strings to the order of preference is kept for the supported cryptolibraries (1. M2Crypto, 2. Python-Rsa, 3. Pycryptodome)
|
||
from setuptools import setup | ||
|
||
# Figure out if the system already has a supported Crypto library |
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.
nah, but I wonder if there's an OR option in setuptools?
setup.py
Outdated
|
||
install_requires = ['libusb1>=1.0.16', 'M2Crypto>=0.21.1,<=0.26.4'], | ||
install_requires = [ | ||
'future', |
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.
where is this used?
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.
Removed, see comments below
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.
Same as above
adb/adb_protocol.py
Outdated
import time | ||
|
||
from io import BytesIO | ||
from future.utils import iteritems |
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.
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.
Just reverted to items below. Now there is no reliance on the future library
adb/adb_protocol.py
Outdated
for cmd_id in ids | ||
} | ||
wire_to_id = {wire: cmd_id for cmd_id, wire in id_to_wire.items()} | ||
wire_to_id = {wire: cmd_id for cmd_id, wire in iteritems(id_to_wire)} |
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.
why go from items
to iteritems
? This isn't a big object so the overhead of the copy is small, and it's correct in py 3 anyway
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.
You're right, no real benefit to iterates here. Reverted to items()
…astboot_debug where chunk_kb was not being passed through
…ng, made build_prop a public property, improved documentation for ConnectDevice
@fahhem I believe I've addressed every one of comments and made changes where appropriate. Please let me know if you have any additional questions and let me know if there's more I can do. Thanks! |
setup.py
Outdated
|
||
install_requires = ['libusb1>=1.0.16', 'M2Crypto>=0.21.1,<=0.26.4'], | ||
install_requires = [ | ||
'future', |
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.
Same as above
DeviceIsAvailable, port_path=port_path, serial=serial, | ||
timeout_ms=default_timeout_ms) | ||
|
||
if 'handle' in kwargs: |
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.
Calling ConnectDevice(handle=...)
is equivalent to Connect(handle)
, so why is Connect()
private? I'm not a big fan of name-mangling-private in Python anyway, nothing's really private in Python anyway, so why not just use one _
and let anyone who wants to hang themselves easier access to the rope?
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.
Agreed, updated the method to be protected ('_') and the documentation around it and its relationship to ConnectDevice
One last comment before it's ready, thanks for the diligent work! |
Oh, and include a change to CONTRIBUTORS adding your info to it |
…called externally. Fixed documentation around the method and its relationship to ConnectDevice()
@fahhem Thanks! Made the change to _Connect and contributors. Edit: Just noticed your comment in setup.py about the 'future' bit, or were your referring to the M2Crypto requirement? Future has been removed from the requirements as its no long used, and I've kept the conditional logic for the crypto library based on whats already installed, defaulting to M2Crypto. Did you want that removed for the previous behavior and just keep other AuthSigners around for customization? Happy either way! |
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.
Ah, that was a comment I accidentally left on the previous version of your code where 'future' was still a requirement, ignore it :)
If you want to do the formatting changes as the next PR, that would be great :) I'll make a new release once the Py3 compatibility PRs are merged or closed, hopefully this week |
Uh oh!
There was an error while loading. Please reload this page.