diff --git a/qrenderdoc/Code/Interface/PersistantConfig.cpp b/qrenderdoc/Code/Interface/PersistantConfig.cpp
index f5b380464..26956be2b 100644
--- a/qrenderdoc/Code/Interface/PersistantConfig.cpp
+++ b/qrenderdoc/Code/Interface/PersistantConfig.cpp
@@ -219,9 +219,6 @@ void PersistantConfig::AddAndroidHosts()
SetConfigSetting("MaxConnectTimeout", QString::number(Android_MaxConnectTimeout));
- SetConfigSetting(lit("Android_AutoPushLayerToApp"),
- Android_AutoPushLayerToApp ? lit("1") : lit("0"));
-
rdcstr androidHosts;
RENDERDOC_EnumerateAndroidDevices(&androidHosts);
for(const QString &hostName :
diff --git a/qrenderdoc/Code/Interface/PersistantConfig.h b/qrenderdoc/Code/Interface/PersistantConfig.h
index c53767ccc..b62571f85 100644
--- a/qrenderdoc/Code/Interface/PersistantConfig.h
+++ b/qrenderdoc/Code/Interface/PersistantConfig.h
@@ -219,8 +219,6 @@ DECLARE_REFLECTION_STRUCT(BugReport);
\
CONFIG_SETTING_VAL(public, int, int, Android_MaxConnectTimeout, 30) \
\
- CONFIG_SETTING_VAL(public, bool, bool, Android_AutoPushLayerToApp, false) \
- \
CONFIG_SETTING_VAL(public, bool, bool, CheckUpdate_AllowChecks, true) \
\
CONFIG_SETTING_VAL(public, bool, bool, CheckUpdate_UpdateAvailable, false) \
@@ -495,12 +493,6 @@ For more information about some of these settings that are user-facing see
Defaults to ``30``.
-.. data:: Android_AutoPushLayerToApp
-
- Whether to automatically push the RenderDoc layer to the application's lib directory when running
- on a device with root access. This can enable debugging of Vulkan applications that didn't already
- package the layer in the APK.
-
.. data:: CheckUpdate_AllowChecks
``True`` if when coloring marker regions in the :class:`EventBrowser`, the whole row should be
diff --git a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp
index b00b147ef..03a2a818a 100644
--- a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp
+++ b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp
@@ -428,11 +428,10 @@ void CaptureDialog::CheckAndroidSetup(QString &filename)
rdcstr host = m_Ctx.Replay().CurrentRemote()->hostname;
RENDERDOC_CheckAndroidPackage(host.c_str(), filename.toUtf8().data(), &m_AndroidFlags);
- const bool missingLibrary = bool(m_AndroidFlags & AndroidFlags::MissingLibrary);
- const bool missingPermissions = bool(m_AndroidFlags & AndroidFlags::MissingPermissions);
- const bool wrongLayerVersion = bool(m_AndroidFlags & AndroidFlags::WrongLayerVersion);
+ const bool debuggable = bool(m_AndroidFlags & AndroidFlags::Debuggable);
+ const bool hasroot = bool(m_AndroidFlags & AndroidFlags::RootAccess);
- if(missingLibrary || missingPermissions || wrongLayerVersion)
+ if(!debuggable && !hasroot)
{
// Check failed - set the warning visible
GUIInvoke::call([this]() {
@@ -442,7 +441,7 @@ void CaptureDialog::CheckAndroidSetup(QString &filename)
}
else
{
- // Check passed - no warnings needed
+ // Check passed, either app is debuggable or we have root - no warnings needed
GUIInvoke::call([this]() {
ui->androidScan->setVisible(false);
ui->androidWarn->setVisible(false);
@@ -458,192 +457,78 @@ void CaptureDialog::androidWarn_mouseClick()
{
QString exe = ui->exePath->text();
- QString caption = tr("Missing RenderDoc requirements");
+ QString caption = tr("Application is not debuggable");
- QString msg = tr("In order to debug on Android, the following problems must be fixed:
");
+ QString msg = tr(R"(In order to debug on Android, the package must be debuggable.
+
+On UE4 you must disable for distribution, on Unity enable development mode.
+
+RenderDoc can try to add the flag for you, which will involve completely reinstalling your package
+as well as re-signing it with a debug key. This method is prone to error and is
+not recommended. It is instead advised to configure your app to be debuggable at build time.
+
+Would you like RenderDoc to try patching your package?
+)");
- 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);
+ QMessageBox::StandardButton prompt = RDDialog::question(this, caption, msg, RDDialog::YesNoCancel);
- if(missingPermissions)
+ if(prompt == QMessageBox::Yes)
{
- msg +=
- tr("Missing permissions
"
- "The target APK must have the following permissions:
"
- "android.permission.INTERNET
");
- }
+ float progress = 0.0f;
+ bool patchSucceeded = false;
- if(missingLibrary)
- {
- msg +=
- tr("Missing library
"
- "The RenderDoc library must be present in the "
- "installed application.
");
- }
+ // call into APK pull, patch, install routine, then continue
+ LambdaThread *patch = new LambdaThread([this, exe, &patchSucceeded, &progress]() {
+ rdcstr host = m_Ctx.Replay().CurrentRemote()->hostname;
+ AndroidFlags result = RENDERDOC_MakeDebuggablePackage(host.c_str(), exe.toUtf8().data(),
+ [&progress](float p) { progress = p; });
- 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
- RDDialog::critical(this, caption, msg);
- return;
- }
-
- // Track whether we tried to push layer directly, to influence text
- bool triedPush = false;
-
- // Track whether to continue with push suggestion dialogue, in case user clicked Cancel
- bool suggestPatch = true;
-
- if(rootAccess)
- {
- // Check whether user has requested automatic pushing
- bool autoPushConfig = m_Ctx.Config().Android_AutoPushLayerToApp;
-
- // Separately, track whether the persistent checkBox is selected
- bool autoPushCheckBox = autoPushConfig;
-
- QMessageBox::StandardButton prompt = QMessageBox::No;
-
- // Only display initial prompt if user has not chosen to push automatically
- if(!autoPushConfig)
- {
- QString rootmsg = msg;
- rootmsg +=
- tr("Your device appears to have root access. If you are only targeting Vulkan, "
- "RenderDoc can try to push the layer directly to your application.
"
- "Would you like RenderDoc to push the layer?
");
-
- QString checkMsg(tr("Automatically push the layer on rooted devices"));
- QCheckBox *cb = new QCheckBox(checkMsg, this);
- cb->setChecked(autoPushCheckBox);
- prompt = RDDialog::questionChecked(this, caption, rootmsg, cb, autoPushCheckBox,
- RDDialog::YesNoCancel);
- }
-
- if(autoPushConfig || prompt == QMessageBox::Yes)
- {
- bool pushSucceeded = false;
- triedPush = true;
-
- // Only update the autoPush setting if Yes was clicked
- if(autoPushCheckBox != m_Ctx.Config().Android_AutoPushLayerToApp)
+ if(result & AndroidFlags::Debuggable)
{
- m_Ctx.Config().Android_AutoPushLayerToApp = autoPushCheckBox;
- m_Ctx.Config().Save();
- }
+ // Sucess!
+ patchSucceeded = true;
- // Call into layer push routine, then continue
- LambdaThread *push = new LambdaThread([this, exe, &pushSucceeded]() {
- rdcstr host = m_Ctx.Replay().CurrentRemote()->hostname;
- if(RENDERDOC_PushLayerToInstalledAndroidApp(host.c_str(), exe.toUtf8().data()))
+ RDDialog::information(this, tr("Patch succeeded!"),
+ tr("The patch process succeeded and the package is ready to debug"));
+ }
+ else
+ {
+ QString failmsg = tr("Something has gone wrong and the patching process failed.
");
+
+ if(result == AndroidFlags::MissingTools)
{
- // Sucess!
- pushSucceeded = true;
-
- RDDialog::information(
- this, tr("Push succeeded!"),
- tr("The push attempt succeeded and
%1 now contains the RenderDoc layer").arg(exe));
+ failmsg +=
+ tr("Tools required for the process were not found. Try configuring the path to your "
+ "android SDK or java JDK in the settings dialog.");
}
- });
-
- push->start();
- if(push->isRunning())
- {
- ShowProgressDialog(this, tr("Pushing layer to %1, please wait...").arg(exe),
- [push]() { return !push->isRunning(); });
- }
- push->deleteLater();
-
- if(pushSucceeded)
- {
- // We should be good from here, no futher prompts
- suggestPatch = false;
- ui->androidWarn->setVisible(false);
- }
- }
- else if(prompt == QMessageBox::Cancel)
- {
- // Cancel skips any other fix prompts
- suggestPatch = false;
- }
- }
-
- if(suggestPatch)
- {
- if(triedPush)
- msg.insert(0, tr("The push attempt failed, so other methods must be used to fix the missing "
- "layer.
"));
-
- msg +=
- tr("To fix this, you should repackage the APK following guidelines on the "
- ""
- "RenderDoc Wiki
"
- "If you are only targeting Vulkan, RenderDoc can try to add the layer for you, "
- "which requires pulling the APK, patching it, uninstalling the original, and "
- "installing the modified version with a debug key. "
- "This works for many debuggable applications, but not all, especially those that "
- "check their integrity before launching.
"
- "Your system will need several tools installed and available to RenderDoc. "
- "Any missing tools will be noted in the log. Follow the steps "
- "here"
- " to get them.
"
- "Would you like RenderDoc to try patching your APK?");
-
- QMessageBox::StandardButton prompt =
- RDDialog::question(this, caption, msg, RDDialog::YesNoCancel);
-
- if(prompt == QMessageBox::Yes)
- {
- float progress = 0.0f;
- bool patchSucceeded = false;
-
- // call into APK pull, patch, install routine, then continue
- LambdaThread *patch = new LambdaThread([this, exe, &patchSucceeded, &progress]() {
- rdcstr host = m_Ctx.Replay().CurrentRemote()->hostname;
- if(RENDERDOC_AddLayerToAndroidPackage(host.c_str(), exe.toUtf8().data(),
- [&progress](float p) { progress = p; }))
+ else if(result == AndroidFlags::ManifestPatchFailure)
{
- // Sucess!
- patchSucceeded = true;
-
- RDDialog::information(
- this, tr("Patch succeeded!"),
- tr("The patch process succeeded and
%1 now contains the RenderDoc layer").arg(exe));
+ failmsg +=
+ tr("The package manifest could not be patched. This is not solveable, you will have "
+ "to rebuild the package with the debuggable flag.");
}
- else
+ else if(result == AndroidFlags::RepackagingAPKFailure)
{
- RDDialog::critical(this, tr("Failed to patch APK"),
- tr("Something has gone wrong and APK patching failed "
- "for:
%1
Check diagnostic log in Help "
- "menu for more details.")
- .arg(exe));
+ failmsg += tr("The package was patched but could not be repackaged and installed.");
}
- });
- patch->start();
- // wait a few ms before popping up a progress bar
- patch->wait(500);
- if(patch->isRunning())
- {
- ShowProgressDialog(this, tr("Patching %1, please wait...").arg(exe),
- [patch]() { return !patch->isRunning(); },
- [&progress]() { return progress; });
+ RDDialog::critical(this, tr("Failed to patch package"), failmsg);
}
- patch->deleteLater();
+ });
- if(patchSucceeded)
- ui->androidWarn->setVisible(false);
+ patch->start();
+ // wait a few ms before popping up a progress bar
+ patch->wait(500);
+ if(patch->isRunning())
+ {
+ ShowProgressDialog(this, tr("Patching %1, please wait...").arg(exe),
+ [patch]() { return !patch->isRunning(); },
+ [&progress]() { return progress; });
}
+ patch->deleteLater();
+
+ if(patchSucceeded)
+ ui->androidWarn->setVisible(false);
}
}
diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp
index 5d5c59cad..83d4888d9 100644
--- a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp
+++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp
@@ -158,7 +158,6 @@ SettingsDialog::SettingsDialog(ICaptureContext &ctx, QWidget *parent)
ui->Android_SDKPath->setText(m_Ctx.Config().Android_SDKPath);
ui->Android_JDKPath->setText(m_Ctx.Config().Android_JDKPath);
ui->Android_MaxConnectTimeout->setValue(m_Ctx.Config().Android_MaxConnectTimeout);
- ui->Android_AutoPushLayerToApp->setChecked(m_Ctx.Config().Android_AutoPushLayerToApp);
ui->TextureViewer_ResetRange->setChecked(m_Ctx.Config().TextureViewer_ResetRange);
ui->TextureViewer_PerTexSettings->setChecked(m_Ctx.Config().TextureViewer_PerTexSettings);
@@ -641,13 +640,6 @@ void SettingsDialog::on_Android_MaxConnectTimeout_valueChanged(double timeout)
m_Ctx.Config().Save();
}
-void SettingsDialog::on_Android_AutoPushLayerToApp_toggled(bool checked)
-{
- m_Ctx.Config().Android_AutoPushLayerToApp = ui->Android_AutoPushLayerToApp->isChecked();
-
- m_Ctx.Config().Save();
-}
-
void SettingsDialog::on_UIStyle_currentIndexChanged(int index)
{
if(index < 0 || index >= StyleData::numAvailable)
diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.h b/qrenderdoc/Windows/Dialogs/SettingsDialog.h
index e3a809a8c..e167e7634 100644
--- a/qrenderdoc/Windows/Dialogs/SettingsDialog.h
+++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.h
@@ -96,7 +96,6 @@ private slots:
void on_Android_MaxConnectTimeout_valueChanged(double timeout);
void on_Android_SDKPath_textEdited(const QString &path);
void on_Android_JDKPath_textEdited(const QString &path);
- void on_Android_AutoPushLayerToApp_toggled(bool checked);
// manual slots
void formatter_valueChanged(int value);
diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.ui b/qrenderdoc/Windows/Dialogs/SettingsDialog.ui
index 8adc15e15..91faba70a 100644
--- a/qrenderdoc/Windows/Dialogs/SettingsDialog.ui
+++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.ui
@@ -73,7 +73,7 @@
QTabWidget::West
- 0
+ 6
true
@@ -1005,7 +1005,7 @@ Only happens if the capture is not in the recent files list.
- -
+
-
Qt::Vertical
@@ -1018,25 +1018,6 @@ Only happens if the capture is not in the recent files list.
- -
-
-
- Automatically push the RenderDoc layer to applications that need it when running on a device with root access.
-This can enable debugging of Vulkan apps that don't already contain the layer.
-
-
- Automatically push RenderDoc layer for Vulkan on devices with root access.
-
-
-
- -
-
-
- Automatically push the RenderDoc layer to applications that need it when running on a device with root access.
-This can enable debugging of Vulkan apps that don't already contain the layer.
-
-
-
-
diff --git a/renderdoc/android/android_patch.cpp b/renderdoc/android/android_patch.cpp
index 06ad1281e..badfe542c 100644
--- a/renderdoc/android/android_patch.cpp
+++ b/renderdoc/android/android_patch.cpp
@@ -86,50 +86,6 @@ bool RemoveAPKSignature(const string &apk)
return true;
}
-bool AddLayerToAPK(const string &apk, const string &layerPath, const string &layerName,
- const string &abi, const string &tmpDir)
-{
- RDCLOG("Adding RenderDoc layer");
-
- std::string aapt = getToolPath(ToolDir::BuildTools, "aapt", false);
-
- // 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())
- {
- RDCERR("Failed to add layer to APK. STDERR: %s", result.strStderror.c_str());
- return false;
- }
-
- return true;
-}
-
bool RealignAPK(const string &apk, string &alignedAPK, const string &tmpDir)
{
std::string zipalign = getToolPath(ToolDir::BuildTools, "zipalign", false);
@@ -383,265 +339,74 @@ bool PullAPK(const string &deviceID, const string &pkgPath, const string &apk)
return false;
}
-bool CheckLayerVersion(const string &deviceID, const string &layerName, const string &remoteLayer)
+bool HasRootAccess(const std::string &deviceID)
{
- RDCDEBUG("Checking layer version of: %s", layerName.c_str());
+ RDCLOG("Checking for root access on %s", deviceID.c_str());
- bool match = false;
+ Process::ProcessResult result = {};
- // 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");
+ // Try switching adb to root and check a few indicators for success
+ // Nothing will fall over if we get a false positive here, it just enables
+ // additional methods of getting things set up.
- string line = trim(result.strStdout);
+ result = adbExecCommand(deviceID, "root");
- if(line.empty())
+ std::string whoami = trim(adbExecCommand(deviceID, "shell whoami").strStdout);
+ if(whoami == "root")
+ return true;
+
+ std::string checksu =
+ trim(adbExecCommand(deviceID, "shell test -e /system/xbin/su && echo found").strStdout);
+ if(checksu == "found")
+ return true;
+
+ return false;
+}
+
+bool IsDebuggable(const std::string &deviceID, const std::string &packageName)
+{
+ RDCLOG("Checking that APK is debuggable");
+
+ std::string info = adbExecCommand(deviceID, "shell dumpsys package " + packageName).strStdout;
+
+ size_t flagsOffset = info.find("pkgFlags=[");
+
+ if(flagsOffset == std::string::npos)
{
- RDCLOG("RenderDoc layer is not versioned, so cannot be checked for compatibility.");
+ RDCERR("Couldn't get pkgFlags from adb");
return false;
}
- std::vector vec;
- split(line, vec, ' ');
- string version = vec[1];
- string hash = vec[5];
+ size_t nextLine = info.find('\n', flagsOffset + 1);
- if(version == FULL_VERSION_STRING && hash == GitVersionHash)
- {
- 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, GitVersionHash);
- }
+ std::string pkgFlags =
+ info.substr(flagsOffset, nextLine == std::string::npos ? nextLine : nextLine - flagsOffset);
- return match;
-}
-
-bool CheckPermissions(const string &dump)
-{
- // TODO: remove this if we are sure that there are no permissions to check.
- return true;
-}
-
-bool CheckAPKPermissions(const string &apk)
-{
- RDCLOG("Checking that APK can be can write to sdcard");
-
- std::string aapt = getToolPath(ToolDir::BuildTools, "aapt", false);
-
- string badging = execCommand(aapt, "dump badging \"" + apk + "\"").strStdout;
-
- if(badging.empty())
- {
- RDCERR("Unable to aapt dump %s", apk.c_str());
- return false;
- }
-
- return CheckPermissions(badging);
-}
-
-bool CheckDebuggable(const string &apk)
-{
- RDCLOG("Checking that APK s debuggable");
-
- std::string aapt = getToolPath(ToolDir::BuildTools, "aapt", false);
-
- string badging = execCommand(aapt, "dump badging \"" + apk + "\"").strStdout;
-
- if(badging.find("application-debuggable") == string::npos)
- {
- RDCERR("APK is not debuggable");
- return false;
- }
-
- return true;
-}
-
-bool CheckInstalledPermissions(const string &deviceID, const string &packageName)
-{
- RDCLOG("Checking installed permissions for %s", packageName.c_str());
-
- string dump = adbExecCommand(deviceID, "shell pm dump " + packageName).strStdout;
- if(dump.empty())
- RDCERR("Unable to pm dump %s", packageName.c_str());
-
- return CheckPermissions(dump);
-}
-
-string DetermineInstalledABI(const string &deviceID, const string &packageName)
-{
- RDCLOG("Checking installed ABI for %s", packageName.c_str());
- string abi;
-
- string dump = adbExecCommand(deviceID, "shell pm dump " + packageName).strStdout;
- if(dump.empty())
- RDCERR("Unable to pm dump %s", packageName.c_str());
-
- // Walk through the output and look for primaryCpuAbi
- std::istringstream contents(dump);
- string line;
- string prefix("primaryCpuAbi=");
- while(std::getline(contents, line))
- {
- line = trim(line);
- if(line.compare(0, prefix.size(), prefix) == 0)
- {
- // Extract the abi
- abi = line.substr(line.find_last_of("=") + 1);
- RDCLOG("primaryCpuAbi found: %s", abi.c_str());
- break;
- }
- }
-
- if(abi.empty())
- RDCERR("Unable to determine installed abi for: %s", packageName.c_str());
-
- return abi;
-}
-
-string FindAndroidLayer(const string &abi, const string &layerName)
-{
- string layer;
-
- // Check known paths for RenderDoc layer
- string exePath;
- FileIO::GetExecutableFilename(exePath);
- string exeDir = dirname(FileIO::GetFullPathname(exePath));
-
- std::vector paths;
-
-#if defined(RENDERDOC_LAYER_PATH)
- string customPath(RENDERDOC_LAYER_PATH);
- RDCLOG("Custom layer path: %s", customPath.c_str());
-
- if(FileIO::IsRelativePath(customPath))
- customPath = exeDir + "/" + customPath;
-
- if(!endswith(customPath, "/"))
- customPath += "/";
-
- // Custom path must point to directory containing ABI folders
- customPath += abi;
- if(!FileIO::exists(customPath.c_str()))
- {
- RDCWARN("Custom layer path does not contain required ABI");
- }
- paths.push_back(customPath + "/" + layerName);
-#endif
-
- string windows = "/android/lib/";
- string linux = "/../share/renderdoc/android/lib/";
- string local = "/../../build-android/renderdoccmd/libs/lib/";
- string macOS = "/../../../../../build-android/renderdoccmd/libs/lib/";
-
- paths.push_back(exeDir + windows + abi + "/" + layerName);
- paths.push_back(exeDir + linux + abi + "/" + layerName);
- paths.push_back(exeDir + local + abi + "/" + layerName);
- paths.push_back(exeDir + macOS + abi + "/" + layerName);
-
- for(uint32_t i = 0; i < paths.size(); i++)
- {
- RDCLOG("Checking for layer in %s", paths[i].c_str());
- if(FileIO::exists(paths[i].c_str()))
- {
- layer = paths[i];
- RDCLOG("Layer found!: %s", layer.c_str());
- break;
- }
- }
-
- if(layer.empty())
- {
- RDCERR(
- "%s missing! RenderDoc for Android will not work without it. "
- "Build your Android ABI in build-android in the root to have it "
- "automatically found and installed.",
- layerName.c_str());
- }
-
- return layer;
-}
-
-std::string GetPathForPackage(const std::string &deviceID, const std::string &packageName)
-{
- std::string pkgPath = trim(adbExecCommand(deviceID, "shell pm path " + packageName).strStdout);
-
- if(pkgPath.empty() || pkgPath.find("package:") != 0 || pkgPath.find("base.apk") == std::string::npos)
- return pkgPath;
-
- pkgPath.erase(pkgPath.begin(), pkgPath.begin() + strlen("package:"));
- pkgPath.erase(pkgPath.end() - strlen("base.apk"), pkgPath.end());
-
- return pkgPath;
+ return pkgFlags.find("DEBUGGABLE") != std::string::npos;
}
};
-using namespace Android;
-extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const char *host,
- const char *exe,
+extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const char *hostname,
+ const char *packageName,
AndroidFlags *flags)
{
- string packageName(basename(string(exe)));
-
int index = 0;
std::string deviceID;
- Android::ExtractDeviceIDAndIndex(host, index, deviceID);
-
- // Find the path to package
- std::string pkgPath = Android::GetPathForPackage(deviceID, packageName) + "lib";
-
- string layerName = "libVkLayer_GLES_RenderDoc.so";
+ Android::ExtractDeviceIDAndIndex(hostname, index, deviceID);
// Reset the flags each time we check
*flags = AndroidFlags::NoFlags;
- bool found = false;
- string layerPath = "";
-
- // Check a debug location only usable by rooted devices, overriding app's layer
- if(SearchForAndroidLibrary(deviceID, "/data/local/debug/vulkan", layerName, layerPath))
- found = true;
-
- // See if the application contains the layer
- if(!found && SearchForAndroidLibrary(deviceID, pkgPath, layerName, layerPath))
- found = true;
-
- // TODO: Add any future layer locations
-
- if(found)
+ if(Android::IsDebuggable(deviceID, basename(std::string(packageName))))
{
-#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
+ *flags |= AndroidFlags::Debuggable;
}
else
{
- RDCWARN("No RenderDoc layer for Vulkan or GLES was found");
- *flags |= AndroidFlags::MissingLibrary;
+ RDCLOG("%s is not debuggable", packageName);
}
- // Next check permissions of the installed application (without pulling the APK)
- if(!CheckInstalledPermissions(deviceID, packageName))
- {
- RDCWARN("Android application does not have required permissions");
- *flags |= AndroidFlags::MissingPermissions;
- }
-
- if(CheckRootAccess(deviceID))
+ if(Android::HasRootAccess(deviceID))
{
RDCLOG("Root access detected");
*flags |= AndroidFlags::RootAccess;
@@ -650,124 +415,9 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const c
return;
}
-extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_PushLayerToInstalledAndroidApp(const char *host,
- const char *exe)
+extern "C" RENDERDOC_API AndroidFlags RENDERDOC_CC RENDERDOC_MakeDebuggablePackage(
+ const char *hostname, const char *packageName, RENDERDOC_ProgressCallback progress)
{
- Process::ProcessResult result = {};
- string packageName(basename(string(exe)));
-
- RDCLOG("Attempting to push RenderDoc layer to %s", packageName.c_str());
-
- int index = 0;
- std::string deviceID;
- Android::ExtractDeviceIDAndIndex(host, index, deviceID);
-
- // Detect which ABI was installed on the device
- string abi = DetermineInstalledABI(deviceID, packageName);
-
- // Find the layer on host
- string layerName("libVkLayer_GLES_RenderDoc.so");
- string layerPath = FindAndroidLayer(abi, layerName);
- if(layerPath.empty())
- return false;
-
- // Determine where to push the layer
- string pkgPath = trim(adbExecCommand(deviceID, "shell pm path " + packageName).strStdout);
-
- // Isolate the app's lib dir
- pkgPath.erase(pkgPath.begin(), pkgPath.begin() + strlen("package:"));
- string libDir = removeFromEnd(pkgPath, "base.apk") + "lib/";
-
- // There will only be one ABI in the lib dir
- string libsAbi = trim(adbExecCommand(deviceID, "shell ls " + libDir).strStdout);
- string layerDst = libDir + libsAbi + "/";
- result = adbExecCommand(deviceID, "push " + layerPath + " " + layerDst);
-
- // Ensure the push succeeded
- string foundLayer;
- return SearchForAndroidLibrary(deviceID, layerDst, layerName, foundLayer);
-}
-
-extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_AddLayerToAndroidPackage(
- const char *host, const char *exe, RENDERDOC_ProgressCallback progress)
-{
- Process::ProcessResult result = {};
- string packageName(basename(string(exe)));
-
- int index = 0;
- std::string deviceID;
- Android::ExtractDeviceIDAndIndex(host, index, deviceID);
-
- // make sure progress is valid so we don't have to check it everywhere
- if(!progress)
- progress = [](float) {};
-
- progress(0.0f);
-
- if(!CheckPatchingRequirements())
- return false;
-
- progress(0.11f);
-
- // Detect which ABI was installed on the device
- string abi = DetermineInstalledABI(deviceID, packageName);
-
- // Find the layer on host
- string layerName("libVkLayer_GLES_RenderDoc.so");
- string layerPath = FindAndroidLayer(abi, layerName);
- if(layerPath.empty())
- return false;
-
- // Find the APK on the device
- std::string apkPath = Android::GetPathForPackage(deviceID, packageName) + "base.apk";
-
- string tmpDir = FileIO::GetTempFolderFilename();
- string origAPK(tmpDir + packageName + ".orig.apk");
- string alignedAPK(origAPK + ".aligned.apk");
-
- progress(0.21f);
-
- // Try the following steps, bailing if anything fails
- if(!PullAPK(deviceID, pkgPath, origAPK))
- return false;
-
- progress(0.31f);
-
- if(!CheckAPKPermissions(origAPK))
- return false;
-
- progress(0.41f);
-
- if(!RemoveAPKSignature(origAPK))
- return false;
-
- progress(0.51f);
-
- if(!AddLayerToAPK(origAPK, layerPath, layerName, abi, tmpDir))
- return false;
-
- progress(0.61f);
-
- if(!RealignAPK(origAPK, alignedAPK, tmpDir))
- return false;
-
- progress(0.71f);
-
- if(!DebugSignAPK(alignedAPK, tmpDir))
- return false;
-
- progress(0.81f);
-
- if(!UninstallOriginalAPK(deviceID, packageName, tmpDir))
- return false;
-
- progress(0.91f);
-
- if(!ReinstallPatchedAPK(deviceID, alignedAPK, abi, packageName, tmpDir))
- return false;
-
- progress(1.0f);
-
- // All clean!
- return true;
+ // stub for now
+ return AndroidFlags::ManifestPatchFailure;
}
diff --git a/renderdoc/android/android_utils.cpp b/renderdoc/android/android_utils.cpp
index 8187a8561..982bbdc94 100644
--- a/renderdoc/android/android_utils.cpp
+++ b/renderdoc/android/android_utils.cpp
@@ -58,42 +58,17 @@ void ExtractDeviceIDAndIndex(const std::string &hostname, int &index, std::strin
deviceID = c;
}
-bool CheckRootAccess(const std::string &deviceID)
+std::string GetPathForPackage(const std::string &deviceID, const std::string &packageName)
{
- RDCLOG("Checking for root access on %s", deviceID.c_str());
+ std::string pkgPath = trim(adbExecCommand(deviceID, "shell pm path " + packageName).strStdout);
- Process::ProcessResult result = {};
+ if(pkgPath.empty() || pkgPath.find("package:") != 0 || pkgPath.find("base.apk") == std::string::npos)
+ return pkgPath;
- // Try switching adb to root and check a few indicators for success
- // Nothing will fall over if we get a false positive here, it just enables
- // additional methods of getting things set up.
+ pkgPath.erase(pkgPath.begin(), pkgPath.begin() + strlen("package:"));
+ pkgPath.erase(pkgPath.end() - strlen("base.apk"), pkgPath.end());
- result = adbExecCommand(deviceID, "root");
-
- std::string whoami = trim(adbExecCommand(deviceID, "shell whoami").strStdout);
- if(whoami == "root")
- return true;
-
- std::string checksu =
- trim(adbExecCommand(deviceID, "shell test -e /system/xbin/su && echo found").strStdout);
- if(checksu == "found")
- return true;
-
- return false;
-}
-
-bool SearchForAndroidLibrary(const std::string &deviceID, const std::string &location,
- const std::string &layerName, std::string &foundLayer)
-{
- RDCLOG("Checking for layers in: %s", location.c_str());
- foundLayer =
- trim(adbExecCommand(deviceID, "shell find " + location + " -name " + layerName).strStdout);
- if(!foundLayer.empty())
- {
- RDCLOG("Found RenderDoc layer in %s", location.c_str());
- return true;
- }
- return false;
+ return pkgPath;
}
std::string GetFriendlyName(std::string deviceID)
diff --git a/renderdoc/android/android_utils.h b/renderdoc/android/android_utils.h
index bd47116f8..86977b535 100644
--- a/renderdoc/android/android_utils.h
+++ b/renderdoc/android/android_utils.h
@@ -48,7 +48,4 @@ std::string getToolPath(ToolDir subdir, const std::string &toolname, bool checkE
bool toolExists(const std::string &path);
std::string GetFriendlyName(std::string deviceID);
-bool CheckRootAccess(const std::string &deviceID);
-bool SearchForAndroidLibrary(const std::string &deviceID, const std::string &location,
- const std::string &layerName, std::string &foundLayer);
};
diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h
index 54cb981e2..e4dd6fb47 100644
--- a/renderdoc/api/replay/renderdoc_replay.h
+++ b/renderdoc/api/replay/renderdoc_replay.h
@@ -2074,17 +2074,13 @@ DOCUMENT("Internal function for starting an android remote server.");
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(const char *device);
DOCUMENT("Internal function for checking remote Android package for requirements");
-extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const char *host,
- const char *exe,
+extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const char *hostname,
+ const char *packageName,
AndroidFlags *flags);
-DOCUMENT("Internal function that attempts to push Vulkan layer to Android application.");
-extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_PushLayerToInstalledAndroidApp(const char *host,
- const char *exe);
-
-DOCUMENT("Internal function that attempts to modify APK contents, adding Vulkan layer.");
-extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_AddLayerToAndroidPackage(
- const char *host, const char *exe, RENDERDOC_ProgressCallback progress);
+DOCUMENT("Internal function that attempts to modify APK contents, adding debuggable flag.");
+extern "C" RENDERDOC_API AndroidFlags RENDERDOC_CC RENDERDOC_MakeDebuggablePackage(
+ const char *hostname, const char *packageName, RENDERDOC_ProgressCallback progress);
DOCUMENT("Internal function that runs unit tests.");
extern "C" RENDERDOC_API int RENDERDOC_CC RENDERDOC_RunUnitTests(const rdcstr &command,
diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h
index 48de2d96a..248365c1f 100644
--- a/renderdoc/api/replay/replay_enums.h
+++ b/renderdoc/api/replay/replay_enums.h
@@ -3529,41 +3529,34 @@ DOCUMENT(R"(A set of flags giving details of the current status of Android traca
There are no problems with the Android application setup.
-.. data:: MissingLibrary
+.. data:: Debuggable
- The RenderDoc library (whether Vulkan layer or OpenGLES library) could not be found in the
- application or system locations.
-
-.. data:: MissingPermissions
-
- The application being checked does not have the requesite permission. Currently there
- are no required permissions.
-
-.. data:: NotDebuggable
-
- The application is not debuggable.
-
-.. data:: WrongLayerVersion
-
- The found RenderDoc layer does not match the server's version.
+ The application is debuggable.
.. data:: RootAccess
The device being targeted has root access.
-.. data:: Unfixable
+.. data:: MissingTools
- The current situation is not fixable automatically and requires user intervention/disambiguation.
+ When patching, some necessary tools were not found.
+
+.. data:: ManifestPatchFailure
+
+ When patching, modifying the manifest file to include the debuggable flag failed.
+
+.. data:: RepackagingAPKFailure
+
+ When patching, repackaging, signing and installing the new package failed.
)");
enum class AndroidFlags : uint32_t
{
NoFlags = 0x0,
- MissingLibrary = 0x1,
- MissingPermissions = 0x2,
- NotDebuggable = 0x4,
- WrongLayerVersion = 0x8,
- RootAccess = 0x10,
- Unfixable = 0x20,
+ Debuggable = 0x1,
+ RootAccess = 0x2,
+ MissingTools = 0x1000,
+ ManifestPatchFailure = 0x2000,
+ RepackagingAPKFailure = 0x4000,
};
BITMASK_OPERATORS(AndroidFlags);