JeffLIrion / adb_shell

A Python implementation of ADB with shell and FileSync functionality.
Apache License 2.0
530 stars 60 forks source link

parallel execute shell command #165

Closed Suwolia closed 3 years ago

Suwolia commented 3 years ago

Signed-off-by: ChenXiang 185807767@qq.com

JeffLIrion commented 3 years ago

There are some linting errors. But those aside, does this work?

https://github.com/JeffLIrion/adb_shell/blob/14ff8907096f812f53cc30f8e8bfae8746c242f9/adb_shell/adb_device.py#L777

Suwolia commented 3 years ago

There are some linting errors. But those aside, does this work?

  • I think a threading.Lock is needed to ensure thread safety
  • adb_info.local_id is always 1; to support multiple streams, I think it needs to be incremented:

https://github.com/JeffLIrion/adb_shell/blob/14ff8907096f812f53cc30f8e8bfae8746c242f9/adb_shell/adb_device.py#L777

I fixed the lint error, and renamed the added methods because I noticed that they don't handle shell streams parallel, actually they keep handling shell streams linearly. method [multi_shell] just open shell command, not try to accept more data, we can call it multiple times. Device will manage the local_id and remote_id automatically. method [streaming_multi_shell_result] is for reading reply from device, and yielding output. These method manage this case: getting result from "adb shell logcat" and "adb shell top" on the same time.

    device.shell('logcat -c')
    logcat_adb_info = device.multi_shell('logcat')
    top_adb_info = device.multi_shell('top')
    try:
        count = 30
        while count > 0:
            adb_info, msg = next(device.streaming_multi_shell_result())
            if adb_info == logcat_adb_info:
                print('logcat result:')
                print(msg)
            if adb_info == top_adb_info:
                print('top result:')
                print(msg)
            count -= 1
    except Exception:
        print('over')
Suwolia commented 3 years ago

seems like I missed some situations, I will commit when I fix it

JeffLIrion commented 3 years ago

This feels like a hack to get your use case to work rather than a robust solution for handling multiple streams. I think that the right way to handle this is to

  1. Increment the local_id each time it sends a command.
  2. Use a dictionary where the keys are (local_id, remote_id) tuples and the values are queues of read packets. Each time you want to read a packet, first check if there is anything in this (local_id, remote_id)'s queue. If so, pop it from the queue. If not, read a packet from the device. If it matches this (local_id, remote_id) then return it; otherwise, add it to the corresponding queue and read another packet.
  3. Use a threading.Lock to make all of this thread safe.

You can certainly monkey patch the class with these methods in your own code, but I don't plan to merge this.