Skip to content

Commit

Permalink
Implement droid
Browse files Browse the repository at this point in the history
  • Loading branch information
Vishal Gowda committed Mar 7, 2017
1 parent 638bb83 commit e5ae0c2
Show file tree
Hide file tree
Showing 12 changed files with 338 additions and 81 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
*.pyc
*.pyc
var/*
File renamed without changes.
5 changes: 4 additions & 1 deletion hedroid/common_settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import os

ROOT_DIR = os.path.dirname(__file__)
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
VAR_DIR = os.path.join(ROOT_DIR, 'var')
CONFIG_PATH = os.path.join(ROOT_DIR, 'droid_config.json')

ZK_HOST = "localhost"
ZK_PORT = "2181"
23 changes: 0 additions & 23 deletions hedroid/worker/droid.py

This file was deleted.

44 changes: 20 additions & 24 deletions hedroid/worker/emulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@

from hedroid.logger import logger
from hedroid.worker.utils import parse_manifest, download_to_temp
from hedroid.worker.executor import Executor


class EmulatorExecutor(object):
def __init__(self, port, avd, **kwargs):
class EmulatorExecutor(Executor):
def __init__(self, port, avd, display, **kwargs):
super(EmulatorExecutor, self).__init__(port)
self.port = port
self.avd = avd

self._proc = None
self.display = display

def adb_wait(self):
logger.debug('Adb shell wait')
cmd = ["adb", "-s", "emulator-{}".format(self.port),
"wait-for-device"]
return subprocess.check_call(cmd, timeout=10)
return subprocess.check_call(cmd, timeout=20)

def sys_boot_wait(self):
logger.debug('Sys boot wait')
Expand All @@ -33,47 +34,42 @@ def sys_boot_wait(self):
break
time.sleep(0.1)

def start(self):
logger.debug('Starting emulator executor')
def _start(self):
# Set DISPLAY variable first
env = os.environ.copy()
if self.display:
env['DISPLAY'] = ':{}'.format(self.display)
cmd = ["emulator", "-port", self.port, "-avd", self.avd,
"-no-boot-anim", "-nojni", "-netfast"]
"-no-boot-anim", "-nojni", "-netfast", "-gpu", "swiftshader",
"-qemu", "-enable-kvm"]
if os.getenv("NO_WINDOW"):
cmd.append("-no-window")
self._proc = subprocess.Popen(
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
env=env,
stdout=self.stdout_fd,
stderr=subprocess.STDOUT,
universal_newlines=True,
)
# Wait till boot
self.adb_wait()
self.sys_boot_wait()
return True

def stop(self):
logger.debug('Stopping emulator executor')
try:
self._proc.terminate()
except:
pass
try:
self._proc.kill()
except:
pass
return proc


class Emulator(object):
def __init__(self, port=None, avd=None):
def __init__(self, port=None, avd=None, display=None):
self.port = port or os.environ.get('ADB_PORT', '5554')
self.avd = avd or os.environ.get('AVD_NAME', 'nexus6-android7')
self.display = display

self.executor = None
self.last_package_maniphest = None

def start(self):
logger.debug('Starting emulator')

self.executor = EmulatorExecutor(self.port, self.avd)
self.executor = EmulatorExecutor(self.port, self.avd, self.display)
self.executor.start()
logger.debug('Emulator ready!')

Expand Down
41 changes: 41 additions & 0 deletions hedroid/worker/executor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import os

from hedroid.logger import logger
from hedroid.common_settings import VAR_DIR


class Executor(object):
def __init__(self, id):
self.id = id
self._proc = None

self.stdout_fd = None

def _start(self):
raise NotImplementedError()

def start(self):
logger.debug('Starting {}'.format(self.__class__.__name__))
self.stdout_fd = open(
os.path.join(
VAR_DIR, "{}-{}".format(
self.__class__.__name__, self.id)), 'w')
self._proc = self._start()

def stop(self):
logger.debug('Stopping {}'.format(self.__class__.__name__))
try:
self._proc.terminate()
except:
pass
try:
self._proc.kill()
except:
pass
# Really wait for child process to terminate
self._proc.wait()
# Prevents zombie processes
del self._proc
self._proc = None
# Close file descriptor
self.stdout_fd.close()
98 changes: 95 additions & 3 deletions hedroid/worker/helpers.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,61 @@
import os

from hedroid.worker.droid import Droid
from hedroid.worker.zk_droid import DroidZkClient
from hedroid.logger import logger
from hedroid.worker.xvfb import Xvfb
from hedroid.worker.emulator import Emulator
from hedroid.worker.vnc import X11VNC
from hedroid.worker.websockify import Websockify


class Droid(object):
def __init__(self, xvfb, emulator, x11vnc, websockify):
self.xvfb = xvfb
self.emulator = emulator
self.x11vnc = x11vnc
self.websockify = websockify

def start(self):
logger.debug('Starting droid')
started = []
try:
self.xvfb.start()
started.append(self.xvfb)
self.emulator.start()
started.append(self.emulator)
self.x11vnc.start()
started.append(self.x11vnc)
self.websockify.start()
started.append(self.websockify)
logger.debug('Droid ready!')
except:
logger.error('Failed to start droid. Reverting')
for proc in started:
try:
proc.stop()
except:
pass

def stop(self):
logger.debug('Stopping droid')
to_stop = [self.websockify, self.x11vnc, self.emulator, self.xvfb]
for proc in to_stop:
try:
proc.stop()
except:
pass
logger.debug('Droid stopped!')


class DroidBuilder(object):
def __init__(self):
self.port = os.environ.get('ADB_PORT', '5554')
self.avd = os.environ.get('AVD_NAME', 'nexus6-android7')
self.display = os.environ.get('DISPLAY_PORT', '1')
self.dpi = 560
self.dim = '720x1280x24'
self.clip = '530x965+15+30'
self.ws_port = 6080

def set_port(self, port):
self.port = port
Expand All @@ -17,9 +65,53 @@ def set_avd(self, avd):
self.avd = avd
return self

def set_display(self, display):
self.display = display
return self

def set_dpi(self, dpi):
self.dpi = dpi
return self

def set_dim(self, dim):
self.dim = dim
return self

def set_clip(self, clip):
self.clip = clip
return self

def set_ws_port(self, port):
self.ws_port = port
return self

def build(self):
xvfb =
emulator = Emulator(port=self.port, avd=self.avd)
xvfb = Xvfb(
display=self.display,
dpi=self.dpi,
dim=self.dim,
)
emulator = Emulator(
port=self.port,
avd=self.avd,
display=self.display,
)
x11vnc = X11VNC(
display=self.display,
clip=self.clip,
)
websockify = Websockify(
source_port=self.ws_port,
target_port=x11vnc.get_rfbport(),
)
# Finally build droid
droid = Droid(
xvfb=xvfb,
emulator=emulator,
x11vnc=x11vnc,
websockify=websockify,
)
return droid


class DroidCoordinator(object):
Expand Down
12 changes: 12 additions & 0 deletions hedroid/worker/thrift_server.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import atexit

import requests
import shutil

from hedroid.logger import logger
from hedroid.worker.helpers import DroidCoordinator, DroidBuilder
from hedroid.worker.utils import get_config, get_public_hostname
from hedroid.worker.utils import get_package_name_from_url
from hedroid.common_settings import VAR_DIR

from hedroid.worker.tgen.droid_service.ttypes import ConnParams, ApplicationException
from hedroid.worker.tgen.droid_service import DroidService
Expand All @@ -20,7 +22,17 @@ class DroidServiceHandler(object):
def __init__(self):
self.coordinator = DroidCoordinator()

def setup_dirs(self):
# setup tmp dir
if os.path.isdir(VAR_DIR):
shutil.rmtree(VAR_DIR)

logger.debug('Setting up temp dir')
os.makedirs(VAR_DIR)

def setup(self):
logger.debug('Setting up dirs')
self.setup_dirs()
logger.debug('Setting up droids')
config = get_config()
builder = DroidBuilder()
Expand Down
7 changes: 3 additions & 4 deletions hedroid/worker/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from requests.exceptions import ConnectTimeout
import subprocess32 as subprocess

from hedroid.common_settings import ROOT_DIR
from hedroid.common_settings import CONFIG_PATH
from hedroid.logger import logger


Expand Down Expand Up @@ -101,10 +101,9 @@ def get_public_hostname():

def get_config():
if CachedGlobals.CONFIG is None:
config_path = os.path.join(ROOT_DIR, 'worker', 'config.json')
err = "Config file not provided for worker"
assert os.path.exists(config_path), err
with open(config_path) as source:
assert os.path.exists(CONFIG_PATH), err
with open(CONFIG_PATH) as source:
CachedGlobals.CONFIG = json.load(source)

return deepcopy(CachedGlobals.CONFIG)
Expand Down
Loading

0 comments on commit e5ae0c2

Please sign in to comment.