Skip to content

Commit

Permalink
supported windows python3
Browse files Browse the repository at this point in the history
  • Loading branch information
yuanchun-li committed Jul 5, 2018
2 parents ba83940 + e6f2819 commit 8df2dfd
Show file tree
Hide file tree
Showing 29 changed files with 1,038 additions and 224 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ Clone this repo and intall with `pip`:

```shell
git clone https://github.com/honeynet/droidbot.git
pip install -e droidbot
cd droidbot/
pip install -e .
```

If successfully installed, you should be able to execute `droidbot -h`.
Expand Down
64 changes: 44 additions & 20 deletions droidbot/adapter/adb.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import subprocess
import logging
import re
from adapter import Adapter
from .adapter import Adapter
import time


class ADBException(Exception):
Expand Down Expand Up @@ -48,7 +49,7 @@ def run_cmd(self, extra_args):
:return: output of adb command
@param extra_args: arguments to run in adb
"""
if isinstance(extra_args, str) or isinstance(extra_args, unicode):
if isinstance(extra_args, str) or isinstance(extra_args, str):
extra_args = extra_args.split()
if not isinstance(extra_args, list):
msg = "invalid arguments: %s\nshould be list or str, %s given" % (extra_args, type(extra_args))
Expand All @@ -61,6 +62,8 @@ def run_cmd(self, extra_args):
self.logger.debug('command:')
self.logger.debug(args)
r = subprocess.check_output(args).strip()
if isinstance(r, bytes):
r = r.decode()
self.logger.debug('return:')
self.logger.debug(r)
return r
Expand All @@ -71,7 +74,7 @@ def shell(self, extra_args):
@param extra_args:
@return: output of adb shell command
"""
if isinstance(extra_args, str) or isinstance(extra_args, unicode):
if isinstance(extra_args, str) or isinstance(extra_args, str):
extra_args = extra_args.split()
if not isinstance(extra_args, list):
msg = "invalid arguments: %s\nshould be list or str, %s given" % (extra_args, type(extra_args))
Expand Down Expand Up @@ -99,15 +102,15 @@ def disconnect(self):
"""
disconnect adb
"""
print "[CONNECTION] %s is disconnected" % self.__class__.__name__
print("[CONNECTION] %s is disconnected" % self.__class__.__name__)

def get_property(self, property):
def get_property(self, property_name):
"""
get the value of property
@param property:
@param property_name:
@return:
"""
return self.shell(["getprop", property])
return self.shell(["getprop", property_name])

def get_model_number(self):
"""
Expand Down Expand Up @@ -149,7 +152,7 @@ def get_display_info(self):
This is a method to obtain display dimensions and density
"""
display_info = {}
logical_display_re = re.compile(".*DisplayViewport\{valid=true, .*orientation=(?P<orientation>\d+),"
logical_display_re = re.compile(".*DisplayViewport{valid=true, .*orientation=(?P<orientation>\d+),"
" .*deviceWidth=(?P<width>\d+), deviceHeight=(?P<height>\d+).*")
dumpsys_display_result = self.shell("dumpsys display")
if dumpsys_display_result is not None:
Expand Down Expand Up @@ -196,8 +199,8 @@ def get_display_info(self):
if float_re.match(d):
density = float(d)
else:
physicalDensityRE = re.compile('Physical density: (?P<density>[\d.]+)', re.MULTILINE)
m = physicalDensityRE.search(self.shell('wm density'))
physical_density_re = re.compile('Physical density: (?P<density>[\d.]+)', re.MULTILINE)
m = physical_density_re.search(self.shell('wm density'))
if m:
density = float(m.group('density'))
if density is not None:
Expand All @@ -215,7 +218,8 @@ def get_enabled_accessibility_services(self):
:return: the enabled service names, each service name is in <package_name>/<service_name> format
"""
r = self.shell("settings get secure enabled_accessibility_services")
return r.strip().split(":")
r = re.sub(r'(?m)^WARNING:.*\n?', '', r)
return r.strip().split(":") if r.strip() != '' else []

def disable_accessibility_service(self, service_name):
"""
Expand All @@ -236,14 +240,34 @@ def enable_accessibility_service(self, service_name):
if service_name not in service_names:
service_names.append(service_name)
self.shell("settings put secure enabled_accessibility_services %s" % ":".join(service_names))
self.shell("settings put secure accessibility_enabled 1")

def enable_accessibility_service_db(self, service_name):
"""
Enable an accessibility service
:param service_name: the service to enable, in <package_name>/<service_name> format
"""
subprocess.check_call(
"adb shell \""
"sqlite3 -batch /data/data/com.android.providers.settings/databases/settings.db \\\""
"DELETE FROM secure WHERE name='enabled_accessibility_services' OR name='accessibility_enabled' "
"OR name='touch_exploration_granted_accessibility_services' OR name='touch_exploration_enabled';"
"INSERT INTO secure (name, value) VALUES "
"('enabled_accessibility_services','" + service_name + "'), "
"('accessibility_enabled','1'), "
"('touch_exploration_granted_accessibility_services','" + service_name + "'), "
"('touch_exploration_enabled','1')\\\";\"", shell=True)
self.shell("stop")
time.sleep(1)
self.shell("start")

def get_installed_apps(self):
"""
Get the package names and apk paths of installed apps on the device
:return: a dict, each key is a package name of an app and each value is the file path to the apk
"""
app_lines = self.shell("pm list packages -f").splitlines()
app_line_re = re.compile('package:(?P<apk_path>[^=]+)=(?P<package>[^=]+)')
app_line_re = re.compile("package:(?P<apk_path>.+)=(?P<package>[^=]+)")
package_to_path = {}
for app_line in app_lines:
m = app_line_re.match(app_line)
Expand All @@ -258,7 +282,8 @@ def get_display_density(self):
else:
return -1.0

def __transform_point_by_orientation(self, (x, y), orientation_orig, orientation_dest):
def __transform_point_by_orientation(self, xy, orientation_orig, orientation_dest):
(x, y) = xy
if orientation_orig != orientation_dest:
if orientation_dest == 1:
_x = x
Expand Down Expand Up @@ -290,7 +315,7 @@ def press(self, key_code):
"""
self.shell("input keyevent %s" % key_code)

def touch(self, x, y, orientation=-1, eventType=DOWN_AND_UP):
def touch(self, x, y, orientation=-1, event_type=DOWN_AND_UP):
if orientation == -1:
orientation = self.get_orientation()
self.shell("input tap %d %d" %
Expand All @@ -299,20 +324,19 @@ def touch(self, x, y, orientation=-1, eventType=DOWN_AND_UP):
def long_touch(self, x, y, duration=2000, orientation=-1):
"""
Long touches at (x, y)
@param duration: duration in ms
@param orientation: the orientation (-1: undefined)
This workaround was suggested by U{HaMi<http://stackoverflow.com/users/2571957/hami>}
"""
self.drag((x, y), (x, y), duration, orientation)

def drag(self, (x0, y0), (x1, y1), duration, orientation=-1):
def drag(self, start_xy, end_xy, duration, orientation=-1):
"""
Sends drag event n PX (actually it's using C{input swipe} command.
@param (x0, y0): starting point in pixel
@param (x1, y1): ending point in pixel
@param start_xy: starting point in pixel
@param end_xy: ending point in pixel
@param duration: duration of the event in ms
@param orientation: the orientation (-1: undefined)
"""
(x0, y0) = start_xy
(x1, y1) = end_xy
if orientation == -1:
orientation = self.get_orientation()
(x0, y0) = self.__transform_point_by_orientation((x0, y0), orientation, self.get_orientation())
Expand Down
121 changes: 121 additions & 0 deletions droidbot/adapter/droidbot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import subprocess

from .adapter import Adapter


class DroidBotConnException(Exception):
"""
Exception in telnet connection
"""
pass


class EOF(Exception):
"""
Exception in telnet connection
"""
pass


class DroidBotConn(Adapter):
"""
a connection with DroidBot.
"""

def __init__(self, device_unique_id,
app_path=None,
device_serial=None,
is_emulator=False,
output_dir=None,
env_policy=None,
policy_name=None,
random_input=False,
script_path=None,
event_count=None,
event_interval=None,
timeout=None,
keep_app=None,
keep_env=False,
cv_mode=False,
debug_mode=False,
profiling_method=None,
grant_perm=False,
enable_accessibility_hard=False,
master=None):
"""
initiate a DroidBot connection
:return:
"""
self.device_unique_id = device_unique_id

self.app_path = app_path
self.device_serial = device_serial
self.is_emulator = is_emulator
self.output_dir = output_dir
self.env_policy = env_policy
self.policy_name = policy_name
self.random_input = random_input
self.script_path = script_path
self.event_count = event_count
self.event_interval = event_interval
self.timeout = timeout
self.keep_app = keep_app
self.keep_env = keep_env
self.cv_mode = cv_mode
self.debug_mode = debug_mode
self.profiling_method = profiling_method
self.grant_perm = grant_perm
self.enable_accessibility_hard = enable_accessibility_hard
self.master = master

self.connected = False
self.droidbot_p = False

def set_up(self):
# start droidbot instance
droidbot_cmd = ["droidbot",
"-d", self.device_serial,
"-a", self.app_path,
"-interval", str(self.event_interval),
"-count", str(self.event_count),
"-policy", "dfs_greedy",
"-grant_perm", "-keep_env", "-random",
"-o", "%s_%d" %
(self.output_dir, self.device_unique_id),
"-use_method_profiling", self.profiling_method,
"-distributed", "worker"]
if self.script_path is not None:
droidbot_cmd += ["-script", self.script_path]
if self.master is not None:
droidbot_cmd += ["-master", self.master]
if self.enable_accessibility_hard:
droidbot_cmd += ["-accessibility_auto"]

self.droidbot_p = subprocess.Popen(droidbot_cmd)
self.pid = self.droidbot_p.pid

def connect(self):
self.connected = True

def check_connectivity(self):
"""
check if DroidBot is connected
:return: True for connected
"""
return self.connected

def disconnect(self):
"""
disconnect telnet
"""
self.connected = False

def tear_down(self):
"""
stop DroidBot instance
"""
self.droidbot_p.kill()


if __name__ == "__main__":
pass
Loading

0 comments on commit 8df2dfd

Please sign in to comment.