mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-24 15:36:33 +00:00
Handle failed APK installation and patching
If "adb install" command is used with "-g" flag, we may get java.lang.SecurityException on some devices because granting runtime permissions at installation time is only allowed for system apps (however we can enable it in the device's Developer options menu). Also, pulling APK from /data/app/ may be restricted. We can workaround by copying the APK to a directory which we can access then try to pull the APK from there.
This commit is contained in:
committed by
Baldur Karlsson
parent
691c115946
commit
6c39b58d0b
@@ -105,19 +105,23 @@ void RemoteHost::CheckStatus()
|
||||
QThread::msleep(15);
|
||||
}
|
||||
|
||||
void RemoteHost::Launch()
|
||||
ReplayStatus RemoteHost::Launch()
|
||||
{
|
||||
ReplayStatus status = ReplayStatus::Succeeded;
|
||||
|
||||
int WAIT_TIME = 2000;
|
||||
|
||||
if(IsADB())
|
||||
{
|
||||
RENDERDOC_StartAndroidRemoteServer(hostname.c_str());
|
||||
status = RENDERDOC_StartAndroidRemoteServer(hostname.c_str());
|
||||
QThread::msleep(WAIT_TIME);
|
||||
return;
|
||||
return status;
|
||||
}
|
||||
|
||||
RDProcess process;
|
||||
process.start(runCommand);
|
||||
process.waitForFinished(WAIT_TIME);
|
||||
process.detach();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -48,8 +48,10 @@ public:
|
||||
DOCUMENT(
|
||||
"Ping the host to check current status - if the server is running, connection status, etc.");
|
||||
void CheckStatus();
|
||||
DOCUMENT("Runs the command specified in :data:`runCommand`.");
|
||||
void Launch();
|
||||
DOCUMENT(
|
||||
"Runs the command specified in :data:`runCommand`. Returns :class:`ReplayStatus` which "
|
||||
"indicates success or the type of failure.");
|
||||
ReplayStatus Launch();
|
||||
|
||||
DOCUMENT("``True`` if a remote server is currently running on this host.");
|
||||
bool serverRunning : 1;
|
||||
|
||||
@@ -171,6 +171,7 @@ void RemoteHost::CheckStatus()
|
||||
{
|
||||
}
|
||||
|
||||
void RemoteHost::Launch()
|
||||
ReplayStatus RemoteHost::Launch()
|
||||
{
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
@@ -1843,7 +1843,11 @@ void MainWindow::switchContext()
|
||||
statusProgress->setMaximum(0);
|
||||
});
|
||||
|
||||
host->Launch();
|
||||
ReplayStatus launchStatus = host->Launch();
|
||||
if(launchStatus != ReplayStatus::Succeeded)
|
||||
{
|
||||
showLaunchError(launchStatus);
|
||||
}
|
||||
|
||||
// check if it's running now
|
||||
host->CheckStatus();
|
||||
@@ -2800,3 +2804,32 @@ bool MainWindow::LoadLayout(int layout)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainWindow::showLaunchError(ReplayStatus status)
|
||||
{
|
||||
QString title;
|
||||
QString message;
|
||||
switch(status)
|
||||
{
|
||||
case ReplayStatus::AndroidGrantPermissionsFailed:
|
||||
title = tr("Permission is required");
|
||||
message = tr("Enable RenderDocCmd to access storage on your device.");
|
||||
break;
|
||||
case ReplayStatus::AndroidABINotFound:
|
||||
title = tr("Failed to install RenderDoc server");
|
||||
message = tr("Couldn't determine supported ABIs.");
|
||||
break;
|
||||
case ReplayStatus::AndroidAPKFolderNotFound:
|
||||
title = tr("Failed to install RenderDoc server");
|
||||
message = tr("APK folder missing.");
|
||||
break;
|
||||
case ReplayStatus::AndroidAPKInstallFailed:
|
||||
title = tr("Failed to install RenderDoc server");
|
||||
message = tr("Couldn't find any installed APKs.");
|
||||
default:
|
||||
title = tr("Failed to install RenderDoc server");
|
||||
message = tr("Unknown error.");
|
||||
break;
|
||||
}
|
||||
GUIInvoke::call(this, [this, title, message]() { RDDialog::warning(this, title, message); });
|
||||
}
|
||||
|
||||
@@ -248,4 +248,6 @@ private:
|
||||
bool SaveLayout(int layout);
|
||||
|
||||
void FillRemotesMenu(QMenu *menu, bool includeLocalhost);
|
||||
|
||||
void showLaunchError(ReplayStatus status);
|
||||
};
|
||||
|
||||
@@ -323,14 +323,16 @@ ExecuteResult StartAndroidPackageForCapture(const char *host, const char *packag
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool InstallRenderDocServer(const std::string &deviceID)
|
||||
ReplayStatus InstallRenderDocServer(const std::string &deviceID)
|
||||
{
|
||||
ReplayStatus status = ReplayStatus::Succeeded;
|
||||
|
||||
std::vector<ABI> abis = GetSupportedABIs(deviceID);
|
||||
|
||||
if(abis.empty())
|
||||
{
|
||||
RDCERR("Couldn't determine supported ABIs for %s", deviceID.c_str());
|
||||
return false;
|
||||
return ReplayStatus::AndroidABINotFound;
|
||||
}
|
||||
|
||||
// Check known paths for RenderDoc server
|
||||
@@ -387,7 +389,7 @@ bool InstallRenderDocServer(const std::string &deviceID)
|
||||
"APK folder 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.");
|
||||
return false;
|
||||
return ReplayStatus::AndroidAPKFolderNotFound;
|
||||
}
|
||||
|
||||
for(ABI abi : abis)
|
||||
@@ -409,7 +411,15 @@ bool InstallRenderDocServer(const std::string &deviceID)
|
||||
"%s missing - ensure you build all ABIs your device can support for full compatibility",
|
||||
apk.c_str());
|
||||
|
||||
adbExecCommand(deviceID, "install -r -g \"" + apk + "\"");
|
||||
Process::ProcessResult adbCheck = adbExecCommand(deviceID, "install -r -g \"" + apk + "\"");
|
||||
|
||||
if(!adbCheck.strStderror.empty())
|
||||
{
|
||||
status = ReplayStatus::AndroidGrantPermissionsFailed;
|
||||
RDCLOG("Failed to install APK. stderr: %s", adbCheck.strStderror.c_str());
|
||||
RDCLOG("Retrying...");
|
||||
adbExecCommand(deviceID, "install -r \"" + apk + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure installation succeeded. We should have as many lines as abis we installed
|
||||
@@ -419,7 +429,7 @@ bool InstallRenderDocServer(const std::string &deviceID)
|
||||
if(adbCheck.strStdout.empty())
|
||||
{
|
||||
RDCERR("Couldn't find any installed APKs. stderr: %s", adbCheck.strStderror.c_str());
|
||||
return false;
|
||||
return ReplayStatus::AndroidAPKInstallFailed;
|
||||
}
|
||||
|
||||
size_t lines = adbCheck.strStdout.find('\n') == std::string::npos ? 1 : 2;
|
||||
@@ -427,7 +437,7 @@ bool InstallRenderDocServer(const std::string &deviceID)
|
||||
if(lines != abis.size())
|
||||
RDCWARN("Installation of some apks failed!");
|
||||
|
||||
return true;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool RemoveRenderDocAndroidServer(const string &deviceID)
|
||||
@@ -601,15 +611,16 @@ extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_IsAndroidSupported(const ch
|
||||
return Android::IsSupported(deviceID);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(const char *device)
|
||||
extern "C" RENDERDOC_API ReplayStatus RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(const char *device)
|
||||
{
|
||||
ReplayStatus status = ReplayStatus::Succeeded;
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
|
||||
Android::ExtractDeviceIDAndIndex(device, index, deviceID);
|
||||
|
||||
if(!Android::IsSupported(deviceID))
|
||||
return;
|
||||
return ReplayStatus::UnknownError;
|
||||
|
||||
std::string packagesOutput = trim(
|
||||
Android::adbExecCommand(deviceID, "shell pm list packages " RENDERDOC_ANDROID_PACKAGE_BASE)
|
||||
@@ -623,10 +634,11 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(co
|
||||
if(packages.size() != abis.size() || !Android::CheckAndroidServerVersion(deviceID))
|
||||
{
|
||||
// If server is not detected or has been removed due to incompatibility, install it
|
||||
if(!Android::InstallRenderDocServer(deviceID))
|
||||
status = Android::InstallRenderDocServer(deviceID);
|
||||
if(status != ReplayStatus::Succeeded && status != ReplayStatus::AndroidGrantPermissionsFailed)
|
||||
{
|
||||
RDCERR("Failed to install RenderDoc server app");
|
||||
return;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,7 +647,7 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(co
|
||||
Android::adbExecCommand(deviceID, "shell am force-stop " + GetRenderDocPackageForABI(abi));
|
||||
|
||||
if(abis.empty())
|
||||
return;
|
||||
return ReplayStatus::AndroidABINotFound;
|
||||
|
||||
Android::adbForwardPorts(index, deviceID, 0, 0, false);
|
||||
Android::ResetCaptureSettings(deviceID);
|
||||
@@ -643,4 +655,5 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(co
|
||||
// launch the first ABI, as the default 'most compatible' package
|
||||
Android::adbExecCommand(deviceID, "shell am start -n " + GetRenderDocPackageForABI(abis[0]) +
|
||||
"/.Loader -e renderdoccmd remoteserver");
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -451,10 +451,22 @@ bool PullAPK(const string &deviceID, const string &pkgPath, const string &apk)
|
||||
elapsed += 1000;
|
||||
}
|
||||
|
||||
RDCERR("Failed to pull APK");
|
||||
RDCLOG("Failed to pull APK");
|
||||
return false;
|
||||
}
|
||||
|
||||
void CopyAPK(const string &deviceID, const string &pkgPath, const string ©Path)
|
||||
{
|
||||
RDCLOG("Copying APK to %s", copyPath.c_str());
|
||||
adbExecCommand(deviceID, "shell cp " + pkgPath + " " + copyPath);
|
||||
}
|
||||
|
||||
void RemoveAPK(const string &deviceID, const string &path)
|
||||
{
|
||||
RDCLOG("Removing APK from %s", path.c_str());
|
||||
adbExecCommand(deviceID, "shell rm -f " + path);
|
||||
}
|
||||
|
||||
bool HasRootAccess(const std::string &deviceID)
|
||||
{
|
||||
RDCLOG("Checking for root access on %s", deviceID.c_str());
|
||||
@@ -572,7 +584,17 @@ extern "C" RENDERDOC_API AndroidFlags RENDERDOC_CC RENDERDOC_MakeDebuggablePacka
|
||||
|
||||
// Try the following steps, bailing if anything fails
|
||||
if(!Android::PullAPK(deviceID, pkgPath, origAPK))
|
||||
return AndroidFlags::ManifestPatchFailure;
|
||||
{
|
||||
// Copy the APK to public storage, then try to pull again
|
||||
std::string copyPath = "/sdcard/" + package + ".copy.apk";
|
||||
Android::CopyAPK(deviceID, pkgPath, copyPath);
|
||||
bool success = Android::PullAPK(deviceID, copyPath, origAPK);
|
||||
Android::RemoveAPK(deviceID, copyPath);
|
||||
if(!success)
|
||||
{
|
||||
return AndroidFlags::ManifestPatchFailure;
|
||||
}
|
||||
}
|
||||
|
||||
progress(0.4f);
|
||||
|
||||
|
||||
@@ -2243,7 +2243,8 @@ DOCUMENT("Internal function for checking android support.");
|
||||
extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_IsAndroidSupported(const char *device);
|
||||
|
||||
DOCUMENT("Internal function for starting an android remote server.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartAndroidRemoteServer(const char *device);
|
||||
extern "C" RENDERDOC_API ReplayStatus 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 *hostname,
|
||||
|
||||
@@ -3078,6 +3078,22 @@ a remote server.
|
||||
|
||||
The API failed to replay the capture, with some runtime error that couldn't be determined until
|
||||
the replay began.
|
||||
|
||||
.. data:: AndroidGrantPermissionsFailed
|
||||
|
||||
Failed to grant runtime permissions when installing Android remote server.
|
||||
|
||||
.. data:: AndroidABINotFound
|
||||
|
||||
Couldn't determine supported ABIs when installing Android remote server.
|
||||
|
||||
.. data:: AndroidAPKFolderNotFound
|
||||
|
||||
Couldn't find the build-android folder which contains the Android remote server APK.
|
||||
|
||||
.. data:: AndroidAPKInstallFailed
|
||||
|
||||
Failed to install Android remote server.
|
||||
)");
|
||||
enum class ReplayStatus : uint32_t
|
||||
{
|
||||
@@ -3101,6 +3117,10 @@ enum class ReplayStatus : uint32_t
|
||||
APIDataCorrupted,
|
||||
APIReplayFailed,
|
||||
JDWPFailure,
|
||||
AndroidGrantPermissionsFailed,
|
||||
AndroidABINotFound,
|
||||
AndroidAPKFolderNotFound,
|
||||
AndroidAPKInstallFailed
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_ENUM(ReplayStatus);
|
||||
|
||||
Reference in New Issue
Block a user