diff --git a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp
index b777aa601..91239f699 100644
--- a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp
+++ b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp
@@ -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.
");
}
+ if(wrongLayerVersion)
+ {
+ msg +=
+ tr("Wrong layer version
"
+ "The RenderDoc library was found, but its version "
+ "does not match that of the host.
");
+ }
+
if(missingPermissions)
{
// Don't prompt for patching if permissions are wrong - we can't fix that
diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h
index 9afb65323..314487224 100644
--- a/renderdoc/api/replay/replay_enums.h
+++ b/renderdoc/api/replay/replay_enums.h
@@ -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);
diff --git a/renderdoc/core/android.cpp b/renderdoc/core/android.cpp
index 268aa2725..7b5a3d39c 100644
--- a/renderdoc/core/android.cpp
+++ b/renderdoc/core/android.cpp
@@ -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 | grep
+ // 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 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,