365 lines
9.4 KiB
PHP
365 lines
9.4 KiB
PHP
<?php
|
|
namespace ATF;
|
|
|
|
use Exception;
|
|
use Amp;
|
|
|
|
interface IDevicePool
|
|
{
|
|
function get() : array;
|
|
}
|
|
|
|
class ApkInstaller
|
|
{
|
|
const ST_IN_PROGRESS = 1;
|
|
const ST_INSTALLED = 2;
|
|
|
|
private string $atf_host;
|
|
private ?string $apk_name;
|
|
private int $max_installs_in_progress;
|
|
private array $installs = array();
|
|
private bool $override_external_files;
|
|
private array $external_files = array();
|
|
|
|
function __construct(
|
|
string $atf_host,
|
|
int $max_installs_in_progress,
|
|
?string $apk_name,
|
|
bool $override_external_files,
|
|
array $external_files
|
|
)
|
|
{
|
|
$this->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;
|
|
}
|
|
}
|
|
|
|
function device_screen(string $atf_host, string $device)
|
|
{
|
|
$screen_file_name = '%{dir}%/'.uniqid("screen_").'.png';
|
|
try
|
|
{
|
|
host_exec($atf_host, "%{adb}% -s $device exec-out screencap -p > $screen_file_name");
|
|
}
|
|
catch(Exception $e)
|
|
{
|
|
return false;
|
|
}
|
|
$data = host_get_file($atf_host, $screen_file_name);
|
|
host_exec($atf_host, "rm -rf $screen_file_name");
|
|
return $data;
|
|
}
|
|
|
|
function device_pss_async(string $atf_host, string $device) : Amp\Promise
|
|
{
|
|
return Amp\call(function() use($atf_host, $device) {
|
|
$res = yield device_mem_async($atf_host, $device);
|
|
return $res['total'];
|
|
});
|
|
}
|
|
|
|
function device_mem_async(string $atf_host, string $device) : Amp\Promise
|
|
{
|
|
return Amp\call(function() use($atf_host, $device) {
|
|
list($code, $lines) = yield host_exec_async($atf_host, "%{adb}% -s $device shell dumpsys meminfo -s %{package_id}%", DEPLOY_OPT_ERR_OK, 20);
|
|
|
|
$res = array(
|
|
'total' => 0,
|
|
'native' => 0,
|
|
'java' => 0,
|
|
'system' => 0,
|
|
'graphics' => 0,
|
|
);
|
|
|
|
if($code !== 0)
|
|
return $res;
|
|
|
|
foreach($lines as $idx => $line)
|
|
{
|
|
$items = preg_split('/\s+/', trim($line));
|
|
if($items && $items[0] === "TOTAL:")
|
|
$res['total'] = intval($items[1]);
|
|
else if($items && $items[0] === "TOTAL" && $items[1] === "PSS:")
|
|
$res['total'] = intval($items[2]);
|
|
else if($items && $items[0] === "Native" && $items[1] === "Heap:")
|
|
$res['native'] = intval($items[2]);
|
|
else if($items && $items[0] === "Java" && $items[1] === "Heap:")
|
|
$res['java'] = intval($items[2]);
|
|
else if($items && $items[0] === "System:")
|
|
$res['system'] = intval($items[1]);
|
|
else if($items && $items[0] === "Graphics:")
|
|
$res['graphics'] = intval($items[1]);
|
|
}
|
|
|
|
return $res;
|
|
});
|
|
}
|
|
|
|
function device_cpuinfo_async(string $atf_host, string $device) : Amp\Promise
|
|
{
|
|
return Amp\call(function() use($atf_host, $device) {
|
|
list($code, $lines) = yield host_exec_async($atf_host, "%{adb}% -s $device shell dumpsys cpuinfo -s %{package_id}%", DEPLOY_OPT_ERR_OK, 20);
|
|
|
|
$res = array(
|
|
'la1' => 0,
|
|
'la5' => 0,
|
|
'la15' => 0
|
|
);
|
|
|
|
if($code !== 0 || count($lines) == 0)
|
|
return $res;
|
|
|
|
foreach($lines as $idx => $line)
|
|
{
|
|
if(strpos($line, 'Load:') !== false)
|
|
{
|
|
$items = explode(':', $line);
|
|
$sub_items = explode('/', $items[1]);
|
|
|
|
$res['la1'] = floatval(trim($sub_items[0]));
|
|
$res['la5'] = floatval(trim($sub_items[1]));
|
|
$res['la15'] = floatval(trim($sub_items[2]));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $res;
|
|
});
|
|
}
|
|
|
|
function device_cputop_async(string $atf_host, string $device) : Amp\Promise
|
|
{
|
|
return Amp\call(function() use($atf_host, $device) {
|
|
list($code, $lines) = yield host_exec_async($atf_host, "%{adb}% -s $device shell top -q -o'%CPU,PID,CMDLINE' -n1 -s1 | grep -w %{package_id}%", DEPLOY_OPT_ERR_OK, 20);
|
|
|
|
$cpu = 0;
|
|
|
|
if($code !== 0 || count($lines) == 0)
|
|
return $cpu;
|
|
|
|
foreach($lines as $idx => $line)
|
|
{
|
|
$items = preg_split('/\s+/', trim($line));
|
|
if(count($items) > 0)
|
|
{
|
|
$cpu = intval($items[0]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $cpu;
|
|
});
|
|
}
|
|
|
|
function device_cpu_freq_min_async(string $atf_host, string $device, int $core_index = 0) : Amp\Promise
|
|
{
|
|
return device_cpu_measure_async($atf_host, $device, "cpuinfo_min_freq", $core_index);
|
|
}
|
|
|
|
function device_cpu_freq_max_async(string $atf_host, string $device, int $core_index = 0) : Amp\Promise
|
|
{
|
|
return device_cpu_measure_async($atf_host, $device, "cpuinfo_max_freq", $core_index);
|
|
}
|
|
|
|
function device_cpu_freq_cur_async(string $atf_host, string $device, int $core_index = 0) : Amp\Promise
|
|
{
|
|
return device_cpu_measure_async($atf_host, $device, "scaling_cur_freq", $core_index);
|
|
}
|
|
|
|
function device_cpu_measure_async(string $atf_host, string $device, string $metric, int $core_index) : Amp\Promise
|
|
{
|
|
return Amp\call(function() use($atf_host, $device, $metric, $core_index) {
|
|
//NOTE: on current devices 16 thermal zone are responsible for GPU temperature probing
|
|
list($code, $lines) = yield host_exec_async($atf_host, "%{adb}% -s $device shell cat /sys/devices/system/cpu/cpu$core_index/cpufreq/$metric", DEPLOY_OPT_ERR_OK, 1);
|
|
|
|
if($code !== 0)
|
|
return 0;
|
|
|
|
foreach($lines as $idx => $line)
|
|
{
|
|
$line = trim($line);
|
|
if(!$line)
|
|
continue;
|
|
return intval($line);
|
|
}
|
|
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
function device_temperature_async(string $atf_host, string $device) : Amp\Promise
|
|
{
|
|
return Amp\call(function() use($atf_host, $device) {
|
|
list($code, $lines) = yield host_exec_async($atf_host, "%{adb}% -s $device shell dumpsys thermalservice", DEPLOY_OPT_ERR_OK, 1);
|
|
|
|
if($code !== 0)
|
|
return array();
|
|
|
|
return device_parse_soc_temps($lines);
|
|
});
|
|
}
|
|
|
|
function device_parse_soc_temps($thermal_output_lines)
|
|
{
|
|
$cpu_temp = null;
|
|
$gpu_temp = null;
|
|
|
|
$hal_section_found = false;
|
|
|
|
foreach($thermal_output_lines as $line)
|
|
{
|
|
if(!$hal_section_found)
|
|
{
|
|
if(strpos($line, 'Current temperatures from HAL:') !== false)
|
|
$hal_section_found = true;
|
|
continue;
|
|
}
|
|
|
|
if(strpos($line, 'mType=0') !== false) //Type 0 indicates CPI
|
|
$cpu_temp = device_parse_thermal_line($line);
|
|
|
|
if(strpos($line, 'mType=1') !== false) //Type 1 indicates GPU
|
|
$gpu_temp = device_parse_thermal_line($line);
|
|
|
|
if($cpu_temp && $gpu_temp)
|
|
break;
|
|
}
|
|
|
|
return [
|
|
'cpu_temp' => $cpu_temp,
|
|
'gpu_temp' => $gpu_temp
|
|
];
|
|
}
|
|
|
|
function device_parse_thermal_line($line)
|
|
{
|
|
return preg_match('/mValue=([^,]+)/', $line, $matches) ? floatval($matches[1]) : null;
|
|
}
|