Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

[Enhancement] Implement Async for adb_commands to Prevent Accidental ADB Overload #135

Closed
caffeinatedMike opened this issue Nov 8, 2018 · 1 comment

Comments

@caffeinatedMike
Copy link

caffeinatedMike commented Nov 8, 2018

When working with this module I've come across a very big hang-up. If the component leveraging this library is built to function asynchronously it becomes cumbersome and quite hack-y to manage the possible adb overload that could result from the component sending successive commands. I've experienced this first hand after converting my module to work asynchronously. In said module, I have an adb_wrapper function used to manage the commands on the component's side. However, that is of little help if this module also implements some sort of async logic. Below is the function currently being used in an attempt to prevent adb overload from the component side.

Full disclosure: This workaround (for lack of async in this module) was provided by @JeffLIrion.

import functools
import logging
import asyncio

_LOGGER = logging.getLogger(__name__)

# The following two variables are set in the the __init__ 
# of the class that will be sending the adb_commands
self._adb_lock = False
self._adb_error = False

def adb_wrapper(func):
    """Wait if previous ADB commands haven't finished."""
    @functools.wraps(func)
    async def _adb_wrapper(self, *args, **kwargs):
        attempts = 0
        while self._adb_lock and attempts < 5:
            attempts += 1
            await asyncio.sleep(1)
        if (attempts == 4 and self._adb_lock) or self._adb_error:
            try:
                _LOGGER.info('Attempting to reconnect to ADB')
                await self._androidtv.connect()
                self._adb_error = False
            except self._exceptions:
                _LOGGER.error('Failed to re-establish the ADB connection; '
                              'will re-attempt in the next update.')
                self._androidtv._adb = None
                self._adb_lock = False
                self._adb_error = True
                return

        self._adb_lock = True
        try:
            returns = await func(self, *args, **kwargs)
        except self._exceptions:
            returns = None
            _LOGGER.error('Failed to execute an ADB command; will attempt to '
                          're-establish the ADB connection in the next update')
            self._androidtv._adb = None
            self._adb_error = True
        finally:
            self._adb_lock = False

        return returns

    return _adb_wrapper

Using this workaround, any function that sends an adb command is retro-fitted with the decorator @adb_command to ensure commands are queued, which originally we thought that would be enough to throttle commands and prevent overloading adb. However, using this workaround has shown mixed results. It seems to work fine on lower-end devices (generic android boxes running android tablet os, android phones, etc), but fails to prevent adb overload on higher-end devices (such as devices with the official Android TV OS & Nvidia Shields).

@caffeinatedMike
Copy link
Author

I'm not led to believe this issue has something to do with an internal issue in the adb_protocol.py file. Therefore, I'm closing this Issue. I've opened a bug ticket #136 as a replacement.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant