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:
baldurk
2017-06-14 16:12:20 +01:00
committed by Baldur Karlsson
parent 06b5b300c3
commit 6423a82d18
13 changed files with 143 additions and 69 deletions
@@ -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);
+1 -1
View File
@@ -109,7 +109,7 @@ void RemoteHost::Launch()
if(IsHostADB())
{
RENDERDOC_StartAndroidRemoteServer();
RENDERDOC_StartAndroidRemoteServer(Hostname.toUtf8().data());
QThread::msleep(WAIT_TIME);
return;
}
-5
View File
@@ -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);
-1
View File
@@ -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();
-7
View File
@@ -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&amp;cs Viewer</string>
</property>
</action>
<action name="action_Start_Android_Remote_Server">
<property name="text">
<string>Start &amp;Android Remote Server</string>
</property>
</action>
<action name="actionShow_Tips">
<property name="text">
<string>Show Tips</string>
+1 -1
View File
@@ -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);
+12 -4
View File
@@ -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;
+2 -1
View File
@@ -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);
+2 -1
View File
@@ -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);
}
+103 -37
View File
@@ -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");
}
+1 -1
View File
@@ -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);
}
}
+7 -3
View File
@@ -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);
}
}
}
+11 -2
View File
@@ -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);
}
}
}