mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-29 21:30:53 +00:00
Add support for multiple connected android devices
* We forward a different range of ports to each device so we can pick and choose which to communicate with based on its index. * The index is encoded in the 'hostname' like so: adb:X:deviceidhere * Whenever we want to interact with an android device we always specify the device, never leave it to a default.
This commit is contained in:
@@ -197,14 +197,12 @@ void PersistantConfig::AddAndroidHosts()
|
||||
{
|
||||
RemoteHost *host = NULL;
|
||||
|
||||
QString fullHostname = lit("adb:") + hostName;
|
||||
|
||||
if(oldHosts.contains(fullHostname))
|
||||
host = oldHosts.take(fullHostname);
|
||||
if(oldHosts.contains(hostName))
|
||||
host = oldHosts.take(hostName);
|
||||
else
|
||||
host = new RemoteHost();
|
||||
|
||||
host->Hostname = fullHostname;
|
||||
host->Hostname = hostName;
|
||||
rdctype::str friendly;
|
||||
RENDERDOC_GetAndroidFriendlyName(hostName.toUtf8().data(), friendly);
|
||||
host->FriendlyName = ToQStr(friendly);
|
||||
|
||||
@@ -109,7 +109,7 @@ void RemoteHost::Launch()
|
||||
|
||||
if(IsHostADB())
|
||||
{
|
||||
RENDERDOC_StartAndroidRemoteServer();
|
||||
RENDERDOC_StartAndroidRemoteServer(Hostname.toUtf8().data());
|
||||
QThread::msleep(WAIT_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1523,11 +1523,6 @@ void MainWindow::on_action_Manage_Remote_Servers_triggered()
|
||||
rm->closeWhenFinished();
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Start_Android_Remote_Server_triggered()
|
||||
{
|
||||
RENDERDOC_StartAndroidRemoteServer();
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Settings_triggered()
|
||||
{
|
||||
SettingsDialog about(m_Ctx, this);
|
||||
|
||||
@@ -113,7 +113,6 @@ private slots:
|
||||
void on_action_Resolve_Symbols_triggered();
|
||||
void on_action_Attach_to_Running_Instance_triggered();
|
||||
void on_action_Manage_Remote_Servers_triggered();
|
||||
void on_action_Start_Android_Remote_Server_triggered();
|
||||
void on_action_Settings_triggered();
|
||||
void on_action_View_Documentation_triggered();
|
||||
void on_action_View_Diagnostic_Log_File_triggered();
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Settings"/>
|
||||
<addaction name="action_Manage_Remote_Servers"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Start_Android_Remote_Server"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_File">
|
||||
<property name="title">
|
||||
@@ -390,11 +388,6 @@
|
||||
<string>Statisti&cs Viewer</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Start_Android_Remote_Server">
|
||||
<property name="text">
|
||||
<string>Start &Android Remote Server</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShow_Tips">
|
||||
<property name="text">
|
||||
<string>Show Tips</string>
|
||||
|
||||
@@ -1434,4 +1434,4 @@ DOCUMENT("Internal function for enumerating android devices.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_EnumerateAndroidDevices(rdctype::str *deviceList);
|
||||
|
||||
DOCUMENT("Internal function for starting an android remote server.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer();
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(const char *device);
|
||||
|
||||
@@ -829,7 +829,11 @@ public:
|
||||
|
||||
if(Android::IsHostADB(m_hostname.c_str()))
|
||||
{
|
||||
string adbStdout = Android::adbExecCommand("shell pm list packages -3");
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::extractDeviceIDAndIndex(m_hostname, index, deviceID);
|
||||
|
||||
string adbStdout = Android::adbExecCommand(deviceID, "shell pm list packages -3");
|
||||
using namespace std;
|
||||
istringstream stdoutStream(adbStdout);
|
||||
string line;
|
||||
@@ -1223,10 +1227,14 @@ RENDERDOC_CreateRemoteServerConnection(const char *host, uint32_t port, IRemoteS
|
||||
{
|
||||
s = "127.0.0.1";
|
||||
|
||||
if(port == RENDERDOC_GetDefaultRemoteServerPort())
|
||||
port += RenderDoc_AndroidPortOffset;
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::extractDeviceIDAndIndex(host, index, deviceID);
|
||||
|
||||
// could parse out an (optional) device name from host+4 here.
|
||||
// each subsequent device gets a new range of ports. The deviceID isn't needed since we already
|
||||
// forwarded the ports to the right devices.
|
||||
if(port == RENDERDOC_GetDefaultRemoteServerPort())
|
||||
port += RenderDoc_AndroidPortOffset * (index + 1);
|
||||
}
|
||||
|
||||
Network::Socket *sock = NULL;
|
||||
|
||||
@@ -735,7 +735,8 @@ extern "C" RENDERDOC_API ITargetControl *RENDERDOC_CC RENDERDOC_CreateTargetCont
|
||||
android = true;
|
||||
s = "127.0.0.1";
|
||||
|
||||
// could parse out an (optional) device name from host+4 here.
|
||||
// we don't need the index or device ID here, because the port is already the right one
|
||||
// forwarded to the right device.
|
||||
}
|
||||
|
||||
Network::Socket *sock = Network::CreateClientSocket(s.c_str(), ident & 0xffff, 750);
|
||||
|
||||
@@ -411,5 +411,6 @@ namespace Android
|
||||
{
|
||||
bool IsHostADB(const char *hostname);
|
||||
uint32_t StartAndroidPackageForCapture(const char *host, const char *package);
|
||||
string adbExecCommand(const string &args);
|
||||
string adbExecCommand(const string &deviceID, const string &args);
|
||||
void extractDeviceIDAndIndex(const string &hostname, int &index, string &deviceID);
|
||||
}
|
||||
|
||||
@@ -448,13 +448,17 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(
|
||||
uint32_t lastIdent = RenderDoc_LastTargetControlPort;
|
||||
if(host != NULL && Android::IsHostADB(host))
|
||||
{
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::extractDeviceIDAndIndex(host, index, deviceID);
|
||||
|
||||
// each subsequent device gets a new range of ports. The deviceID isn't needed since we already
|
||||
// forwarded the ports to the right devices.
|
||||
if(nextIdent == RenderDoc_FirstTargetControlPort)
|
||||
nextIdent += RenderDoc_AndroidPortOffset;
|
||||
lastIdent += RenderDoc_AndroidPortOffset;
|
||||
nextIdent += RenderDoc_AndroidPortOffset * (index + 1);
|
||||
lastIdent += RenderDoc_AndroidPortOffset * (index + 1);
|
||||
|
||||
s = "127.0.0.1";
|
||||
|
||||
// could parse out an (optional) device name from host+4 here.
|
||||
}
|
||||
|
||||
for(; nextIdent <= lastIdent; nextIdent++)
|
||||
@@ -547,7 +551,29 @@ bool IsHostADB(const char *hostname)
|
||||
{
|
||||
return !strncmp(hostname, "adb:", 4);
|
||||
}
|
||||
string adbExecCommand(const string &args)
|
||||
void extractDeviceIDAndIndex(const string &hostname, int &index, string &deviceID)
|
||||
{
|
||||
if(!IsHostADB(hostname.c_str()))
|
||||
return;
|
||||
|
||||
const char *c = hostname.c_str();
|
||||
c += 4;
|
||||
|
||||
index = atoi(c);
|
||||
|
||||
c = strchr(c, ':');
|
||||
|
||||
if(!c)
|
||||
{
|
||||
index = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
c++;
|
||||
|
||||
deviceID = c;
|
||||
}
|
||||
string adbExecCommand(const string &device, const string &args)
|
||||
{
|
||||
string adbExePath = RenderDoc::Inst().GetConfigSetting("adbExePath");
|
||||
if(adbExePath.empty())
|
||||
@@ -561,36 +587,53 @@ string adbExecCommand(const string &args)
|
||||
adbExePath.append("adb");
|
||||
}
|
||||
Process::ProcessResult result;
|
||||
Process::LaunchProcess(adbExePath.c_str(), "", args.c_str(), &result);
|
||||
string deviceArgs;
|
||||
if(device.empty())
|
||||
deviceArgs = args;
|
||||
else
|
||||
deviceArgs = StringFormat::Fmt("-s %s %s", device.c_str(), args.c_str());
|
||||
Process::LaunchProcess(adbExePath.c_str(), "", deviceArgs.c_str(), &result);
|
||||
RDCLOG("COMMAND: adb %s", args.c_str());
|
||||
if(result.strStdout.length())
|
||||
// This could be an error (i.e. no package), or just regular output from adb devices.
|
||||
RDCLOG("STDOUT:\n%s", result.strStdout.c_str());
|
||||
return result.strStdout;
|
||||
}
|
||||
void adbForwardPorts()
|
||||
string adbGetDeviceList()
|
||||
{
|
||||
adbExecCommand(StringFormat::Fmt("forward tcp:%i tcp:%i",
|
||||
RenderDoc_RemoteServerPort + RenderDoc_AndroidPortOffset,
|
||||
return adbExecCommand("", "devices");
|
||||
}
|
||||
void adbForwardPorts(int index, const std::string &deviceID)
|
||||
{
|
||||
int offs = RenderDoc_AndroidPortOffset * (index + 1);
|
||||
adbExecCommand(deviceID,
|
||||
StringFormat::Fmt("forward tcp:%i tcp:%i", RenderDoc_RemoteServerPort + offs,
|
||||
RenderDoc_RemoteServerPort));
|
||||
adbExecCommand(StringFormat::Fmt("forward tcp:%i tcp:%i",
|
||||
RenderDoc_FirstTargetControlPort + RenderDoc_AndroidPortOffset,
|
||||
adbExecCommand(deviceID,
|
||||
StringFormat::Fmt("forward tcp:%i tcp:%i", RenderDoc_FirstTargetControlPort + offs,
|
||||
RenderDoc_FirstTargetControlPort));
|
||||
}
|
||||
uint32_t StartAndroidPackageForCapture(const char *host, const char *package)
|
||||
{
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::extractDeviceIDAndIndex(host, index, deviceID);
|
||||
|
||||
string packageName = basename(string(package)); // Remove leading '/' if any
|
||||
|
||||
adbExecCommand("shell am force-stop " + packageName);
|
||||
adbForwardPorts();
|
||||
adbExecCommand("shell setprop debug.vulkan.layers VK_LAYER_RENDERDOC_Capture");
|
||||
adbExecCommand("shell pm grant " + packageName +
|
||||
" android.permission.WRITE_EXTERNAL_STORAGE"); // Creating the capture file
|
||||
adbExecCommand("shell pm grant " + packageName +
|
||||
" android.permission.READ_EXTERNAL_STORAGE"); // Reading the capture thumbnail
|
||||
adbExecCommand("shell monkey -p " + packageName + " -c android.intent.category.LAUNCHER 1");
|
||||
adbExecCommand(deviceID, "shell am force-stop " + packageName);
|
||||
adbForwardPorts(index, deviceID);
|
||||
adbExecCommand(deviceID, "shell setprop debug.vulkan.layers VK_LAYER_RENDERDOC_Capture");
|
||||
// Creating the capture file
|
||||
adbExecCommand(deviceID,
|
||||
"shell pm grant " + packageName + " android.permission.WRITE_EXTERNAL_STORAGE");
|
||||
// Reading the capture thumbnail
|
||||
adbExecCommand(deviceID,
|
||||
"shell pm grant " + packageName + " android.permission.READ_EXTERNAL_STORAGE");
|
||||
adbExecCommand(deviceID,
|
||||
"shell monkey -p " + packageName + " -c android.intent.category.LAUNCHER 1");
|
||||
|
||||
uint32_t ret = RenderDoc_FirstTargetControlPort + RenderDoc_AndroidPortOffset;
|
||||
uint32_t ret = RenderDoc_FirstTargetControlPort + RenderDoc_AndroidPortOffset * (index + 1);
|
||||
uint32_t elapsed = 0,
|
||||
timeout = 1000 *
|
||||
RDCMAX(5, atoi(RenderDoc::Inst().GetConfigSetting("MaxConnectTimeout").c_str()));
|
||||
@@ -609,7 +652,7 @@ uint32_t StartAndroidPackageForCapture(const char *host, const char *package)
|
||||
}
|
||||
|
||||
// Let the app pickup the setprop before we turn it back off for replaying.
|
||||
adbExecCommand("shell setprop debug.vulkan.layers :");
|
||||
adbExecCommand(deviceID, "shell setprop debug.vulkan.layers :");
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -619,13 +662,24 @@ using namespace Android;
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_GetAndroidFriendlyName(const rdctype::str &device,
|
||||
rdctype::str &friendly)
|
||||
{
|
||||
string manuf = adbExecCommand(
|
||||
StringFormat::Fmt("-s %s shell getprop ro.product.manufacturer", device.c_str()));
|
||||
string model =
|
||||
adbExecCommand(StringFormat::Fmt("-s %s shell getprop ro.product.model", device.c_str()));
|
||||
if(!IsHostADB(device.c_str()))
|
||||
{
|
||||
RDCERR("Calling RENDERDOC_GetAndroidFriendlyName with non-android device: %s", device.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
manuf = trim(manuf);
|
||||
model = trim(model);
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::extractDeviceIDAndIndex(device.c_str(), index, deviceID);
|
||||
|
||||
if(deviceID.empty())
|
||||
{
|
||||
RDCERR("Failed to get android device and index from: %s", device.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
string manuf = trim(adbExecCommand(deviceID, "shell getprop ro.product.manufacturer"));
|
||||
string model = trim(adbExecCommand(deviceID, "shell getprop ro.product.model"));
|
||||
|
||||
std::string combined;
|
||||
|
||||
@@ -646,7 +700,9 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_GetAndroidFriendlyName(cons
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_EnumerateAndroidDevices(rdctype::str *deviceList)
|
||||
{
|
||||
string adbStdout = adbExecCommand("devices");
|
||||
string adbStdout = adbGetDeviceList();
|
||||
|
||||
int idx = 0;
|
||||
|
||||
using namespace std;
|
||||
istringstream stdoutStream(adbStdout);
|
||||
@@ -660,23 +716,33 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_EnumerateAndroidDevices(rdc
|
||||
{
|
||||
if(ret.length())
|
||||
ret += ",";
|
||||
ret += tokens[0];
|
||||
|
||||
ret += StringFormat::Fmt("adb:%d:%s", idx, tokens[0].c_str());
|
||||
|
||||
// Forward the ports so we can see if a remoteserver/captured app is already running.
|
||||
adbForwardPorts(idx, tokens[0]);
|
||||
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
if(ret.size())
|
||||
adbForwardPorts(); // Forward the ports so we can see if a remoteserver/captured app is
|
||||
// already running.
|
||||
|
||||
*deviceList = ret;
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer()
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(const char *device)
|
||||
{
|
||||
adbExecCommand("shell am force-stop org.renderdoc.renderdoccmd");
|
||||
adbForwardPorts();
|
||||
adbExecCommand("shell setprop debug.vulkan.layers :");
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
|
||||
// legacy code - delete when C# UI is gone. Handle a NULL or empty device string
|
||||
if(device || device[0] == '\0')
|
||||
Android::extractDeviceIDAndIndex(device, index, deviceID);
|
||||
|
||||
adbExecCommand(deviceID, "shell am force-stop org.renderdoc.renderdoccmd");
|
||||
adbForwardPorts(index, deviceID);
|
||||
adbExecCommand(deviceID, "shell setprop debug.vulkan.layers :");
|
||||
adbExecCommand(
|
||||
deviceID,
|
||||
"shell am start -n org.renderdoc.renderdoccmd/.Loader -e renderdoccmd remoteserver");
|
||||
}
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ namespace renderdocui.Code
|
||||
foreach(string hostName in androidHosts)
|
||||
{
|
||||
RemoteHost host = new RemoteHost();
|
||||
host.Hostname = "adb:" + hostName;
|
||||
host.Hostname = hostName;
|
||||
RemoteHosts.Add(host);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace renderdoc
|
||||
private static extern ReplaySupport RENDERDOC_EnumerateAndroidDevices(IntPtr driverName);
|
||||
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern ReplaySupport RENDERDOC_StartAndroidRemoteServer();
|
||||
private static extern ReplaySupport RENDERDOC_StartAndroidRemoteServer(IntPtr device);
|
||||
|
||||
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void RENDERDOC_StartSelfHostCapture(IntPtr dllname);
|
||||
@@ -410,9 +410,13 @@ namespace renderdoc
|
||||
return driverList.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public static void StartAndroidRemoteServer()
|
||||
public static void StartAndroidRemoteServer(string device)
|
||||
{
|
||||
RENDERDOC_StartAndroidRemoteServer();
|
||||
IntPtr device_mem = CustomMarshal.MakeUTF8String(device);
|
||||
|
||||
RENDERDOC_StartAndroidRemoteServer(device_mem);
|
||||
|
||||
CustomMarshal.Free(device_mem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ namespace renderdocui.Windows
|
||||
|
||||
private List<LiveCapture> m_LiveCaptures = new List<LiveCapture>();
|
||||
|
||||
private RemoteHost m_SelectedHost = null;
|
||||
|
||||
private string InformationalVersion
|
||||
{
|
||||
get
|
||||
@@ -1203,7 +1205,9 @@ namespace renderdocui.Windows
|
||||
{
|
||||
ToolStripItem item = sender as ToolStripItem;
|
||||
|
||||
if(item == null)
|
||||
m_SelectedHost = null;
|
||||
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
RemoteHost host = item.Tag as RemoteHost;
|
||||
@@ -1264,6 +1268,8 @@ namespace renderdocui.Windows
|
||||
|
||||
statusText.Text = "Checking remote server status...";
|
||||
|
||||
m_SelectedHost = host;
|
||||
|
||||
Thread th = Helpers.NewThread(new ThreadStart(() =>
|
||||
{
|
||||
// see if the server is up
|
||||
@@ -2022,7 +2028,10 @@ namespace renderdocui.Windows
|
||||
|
||||
private void startAndroidRemoteServerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
StaticExports.StartAndroidRemoteServer();
|
||||
string device = "";
|
||||
if (m_SelectedHost != null)
|
||||
device = m_SelectedHost.Hostname;
|
||||
StaticExports.StartAndroidRemoteServer(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user