atf_host = $atf_host; $this->max_installs_in_progress = $max_installs_in_progress; $this->apk_name = $apk_name; $this->override_external_files = $override_external_files; $this->external_files = $external_files; } function isInstalled(string $device) { return isset($this->installs[$device]) && $this->installs[$device] == self::ST_INSTALLED; } function forgetInstall(string $device) { unset($this->installs[$device]); } function countInstallsInProgress() { $c = 0; foreach($this->installs as $status) if($status == self::ST_IN_PROGRESS) ++$c; return $c; } function installAsync(string $device, bool $force = false) : Amp\Promise { return Amp\call(function() use($device, $force) { while($this->countInstallsInProgress() >= $this->max_installs_in_progress) yield Amp\delay(1000); if($force) unset($this->installs[$device]); if(isset($this->installs[$device])) return; $this->installs[$device] = self::ST_IN_PROGRESS; try { yield host_exec_async($this->atf_host, "%{adb}% -s $device shell am force-stop %{package_id}%", DEPLOY_OPT_ERR_OK); if($this->apk_name !== null) { yield host_exec_async($this->atf_host, "%{adb}% -s $device uninstall %{package_id}%", DEPLOY_OPT_ERR_OK, 30); yield host_exec_async($this->atf_host, "%{adb}% -s $device install -r %{dir}%/{$this->apk_name}", 0, 300); //delete overrides only if there's a new apk file uploaded yield del_external_files_async($this->atf_host, $device, $this->external_files); } if($this->override_external_files) yield put_external_files_async($this->atf_host, $device, $this->external_files); $this->installs[$device] = self::ST_INSTALLED; } catch(Exception $e) { err("Error during install *$device*: " . $e->getMessage()); unset($this->installs[$device]); throw $e; } }); } function getSize() { list($status, $lines) = host_exec($this->atf_host, "ls -sd -- %{dir}%/{$this->apk_name}", DEPLOY_OPT_ERR_OK|DEPLOY_OPT_SILENT); if($status != 0) return 0; $items = explode(' ', $lines[0]); //ls -s returns size in blocks where each block is 512 bytes long return intval($items[0])*512; } } class AdbDevicePool implements IDevicePool { private string $atf_host; function __construct(string $atf_host) { $this->atf_host = $atf_host; } function get() : array { return get_devices($this->atf_host); } } class FixedDevicePool implements IDevicePool { private array $devices; function __construct(array $devices) { $this->devices = $devices; } function get() : array { return $this->devices; } } class CachedDevices implements IDevicePool { private IDevicePool $provider; private ?array $cached = null; private int $last_cache_time; private int $keep_cache_time; function __construct(IDevicePool $provider, int $keep_cache_time) { $this->provider = $provider; $this->keep_cache_time = $keep_cache_time; } function get() : array { if($this->cached === null || (time() - $this->last_cache_time) > $this->keep_cache_time) { $this->cached = $this->provider->get(); $this->last_cache_time = time(); } return $this->cached; } }