Add version checking to Android workflow

* Tag the RenderDoc layer with a version string that
  matches the host, including git hash.
* In developer builds, check the version when scanning the
  application for RenderDoc support.
* Pass the warning back to the UI to offer ways to fix.
* Update APK patching to remove existing layer.
This commit is contained in:
Cody Northrop
2017-09-20 10:04:20 -06:00
committed by Baldur Karlsson
parent 03a0a06f60
commit 82f4e82155
3 changed files with 111 additions and 13 deletions
+11 -1
View File
@@ -430,8 +430,9 @@ void CaptureDialog::CheckAndroidSetup(QString &filename)
const bool missingLibrary = bool(m_AndroidFlags & AndroidFlags::MissingLibrary);
const bool missingPermissions = bool(m_AndroidFlags & AndroidFlags::MissingPermissions);
const bool wrongLayerVersion = bool(m_AndroidFlags & AndroidFlags::WrongLayerVersion);
if(missingLibrary || missingPermissions)
if(missingLibrary || missingPermissions || wrongLayerVersion)
{
// Check failed - set the warning visible
GUIInvoke::call([this]() {
@@ -463,6 +464,7 @@ void CaptureDialog::androidWarn_mouseClick()
bool missingPermissions = bool(m_AndroidFlags & AndroidFlags::MissingPermissions);
bool missingLibrary = bool(m_AndroidFlags & AndroidFlags::MissingLibrary);
bool wrongLayerVersion = bool(m_AndroidFlags & AndroidFlags::WrongLayerVersion);
bool rootAccess = bool(m_AndroidFlags & AndroidFlags::RootAccess);
if(missingPermissions)
@@ -481,6 +483,14 @@ void CaptureDialog::androidWarn_mouseClick()
"installed application.<br><br>");
}
if(wrongLayerVersion)
{
msg +=
tr("<b>Wrong layer version</b><br>"
"The RenderDoc library was found, but its version "
"does not match that of the host.<br><br>");
}
if(missingPermissions)
{
// Don't prompt for patching if permissions are wrong - we can't fix that
+7 -2
View File
@@ -3508,6 +3508,10 @@ DOCUMENT(R"(A set of flags giving details of the current status of Android traca
The application is not debuggable.
.. data:: WrongLayerVersion
The found RenderDoc layer does not match the server's version.
.. data:: RootAccess
The device being targeted has root access.
@@ -3522,8 +3526,9 @@ enum class AndroidFlags : uint32_t
MissingLibrary = 0x1,
MissingPermissions = 0x2,
NotDebuggable = 0x4,
RootAccess = 0x8,
Unfixable = 0x10,
WrongLayerVersion = 0x8,
RootAccess = 0x10,
Unfixable = 0x20,
};
BITMASK_OPERATORS(AndroidFlags);
+93 -10
View File
@@ -28,6 +28,9 @@
#include "core/core.h"
#include "strings/string_utils.h"
extern "C" RENDERDOC_API const char RENDERDOC_Version_Tag_String[] =
"RenderDoc_build_version: " FULL_VERSION_STRING " from git commit " GIT_COMMIT_HASH;
namespace Android
{
enum class ToolDir
@@ -376,12 +379,13 @@ uint32_t StartAndroidPackageForCapture(const char *host, const char *package)
return ret;
}
bool SearchForAndroidLayer(const string &deviceID, const string &location, const string &layerName)
bool SearchForAndroidLayer(const string &deviceID, const string &location, const string &layerName,
string &foundLayer)
{
RDCLOG("Checking for layers in: %s", location.c_str());
string findLayer =
adbExecCommand(deviceID, "shell find " + location + " -name " + layerName).strStdout;
if(!findLayer.empty())
foundLayer =
trim(adbExecCommand(deviceID, "shell find " + location + " -name " + layerName).strStdout);
if(!foundLayer.empty())
{
RDCLOG("Found RenderDoc layer in %s", location.c_str());
return true;
@@ -444,6 +448,29 @@ bool AddLayerToAPK(const string &apk, const string &layerPath, const string &lay
// Run aapt from the directory containing "lib" so the relative paths are good
string relativeLayer("lib/" + abi + "/" + layerName);
string workDir = removeFromEnd(layerPath, relativeLayer);
// If the layer was already present in the APK, we need to remove it first
Process::ProcessResult contents = execCommand(aapt, "list \"" + apk + "\"", workDir);
if(contents.strStdout.empty())
{
RDCERR("Failed to list contents of APK. STDERR: %s", contents.strStderror.c_str());
return false;
}
if(contents.strStdout.find(relativeLayer) != std::string::npos)
{
RDCLOG("Removing existing layer from APK before trying to add");
Process::ProcessResult remove =
execCommand(aapt, "remove \"" + apk + "\" " + relativeLayer, workDir);
if(!remove.strStdout.empty())
{
RDCERR("Failed to remove existing layer from APK. STDERR: %s", remove.strStderror.c_str());
return false;
}
}
// Add the RenderDoc layer
Process::ProcessResult result = execCommand(aapt, "add \"" + apk + "\" " + relativeLayer, workDir);
if(result.strStdout.empty())
@@ -708,6 +735,49 @@ bool PullAPK(const string &deviceID, const string &pkgPath, const string &apk)
return false;
}
bool CheckLayerVersion(const string &deviceID, const string &layerName, const string &remoteLayer)
{
RDCDEBUG("Checking layer version of: %s", layerName.c_str());
bool match = false;
// Use 'strings' command on the device to find the layer's build version
// i.e. strings -n <tag length> <layer> | grep <tag marker>
// Subtract 5 to provide a bit of wiggle room on version length
Process::ProcessResult result = adbExecCommand(
deviceID, "shell strings -n " +
StringFormat::Fmt("%u", strlen(RENDERDOC_Version_Tag_String) - 5) + " " +
remoteLayer + " | grep RenderDoc_build_version");
string line = trim(result.strStdout);
if(line.empty())
{
RDCLOG("RenderDoc layer is not versioned, so cannot be checked for compatibility.");
return false;
}
std::vector<string> vec;
split(line, vec, ' ');
string version = vec[1];
string hash = vec[5];
if(version == FULL_VERSION_STRING && hash == GIT_COMMIT_HASH)
{
RDCLOG("RenderDoc layer version (%s) and git hash (%s) match.", version.c_str(), hash.c_str());
match = true;
}
else
{
RDCLOG(
"RenderDoc layer version (%s) and git hash (%s) do NOT match the host version (%s) or git "
"hash (%s).",
version.c_str(), hash.c_str(), FULL_VERSION_STRING, GIT_COMMIT_HASH);
}
return match;
}
bool CheckPermissions(const string &dump)
{
// TODO: remove this if we are sure that there are no permissions to check.
@@ -1188,18 +1258,30 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const c
*flags = AndroidFlags::NoFlags;
bool found = false;
string layerPath = "";
// First, see if the application contains the layer
if(SearchForAndroidLayer(deviceID, pkgPath, layerName))
// Check a debug location only usable by rooted devices, overriding app's layer
if(SearchForAndroidLayer(deviceID, "/data/local/debug/vulkan", layerName, layerPath))
found = true;
// Next, check a debug location only usable by rooted devices
if(!found && SearchForAndroidLayer(deviceID, "/data/local/debug/vulkan", layerName))
// See if the application contains the layer
if(!found && SearchForAndroidLayer(deviceID, pkgPath, layerName, layerPath))
found = true;
// TODO: Add any future layer locations
if(!found)
if(found)
{
#if ENABLED(RDOC_DEVEL)
// Check the version of the layer found
if(!CheckLayerVersion(deviceID, layerName, layerPath))
{
RDCWARN("RenderDoc layer found, but version does not match");
*flags |= AndroidFlags::WrongLayerVersion;
}
#endif
}
else
{
RDCWARN("No RenderDoc layer for Vulkan or GLES was found");
*flags |= AndroidFlags::MissingLibrary;
@@ -1255,7 +1337,8 @@ extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_PushLayerToInstalledAndroid
result = adbExecCommand(deviceID, "push " + layerPath + " " + layerDst);
// Ensure the push succeeded
return SearchForAndroidLayer(deviceID, layerDst, layerName);
string foundLayer;
return SearchForAndroidLayer(deviceID, layerDst, layerName, foundLayer);
}
extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_AddLayerToAndroidPackage(const char *host,