mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-08 15:51:01 +00:00
Allow choosing activities for an android program. Closes #1387
This commit is contained in:
@@ -108,12 +108,20 @@ void CaptureDialog::PopulateMostRecent()
|
||||
if(!settings.executable.isEmpty())
|
||||
{
|
||||
ui->loadLastCapture->setEnabled(true);
|
||||
if(settings.executable.indexOf('/') < 0 && settings.executable.indexOf('\\') < 0)
|
||||
ui->loadLastCapture->setText(tr("Load Last Settings - %1").arg(QString(settings.executable)));
|
||||
|
||||
QString exe = settings.executable;
|
||||
|
||||
// if the executable isn't a path, display the full name
|
||||
bool fullName = (exe.indexOf(QLatin1Char('/')) < 0 && exe.indexOf(QLatin1Char('\\')) < 0);
|
||||
|
||||
// if it's not a windows path and only contains one '/', it's an android package so also
|
||||
// display the full name
|
||||
fullName |= (exe.indexOf(QLatin1Char('\\')) < 0 && exe.count(QLatin1Char('/')) == 1);
|
||||
|
||||
if(fullName)
|
||||
ui->loadLastCapture->setText(tr("Load Last Settings - %1").arg(exe));
|
||||
else
|
||||
ui->loadLastCapture->setText(
|
||||
tr("Load Last Settings - %1")
|
||||
.arg(QFileInfo(QString(settings.executable)).completeBaseName()));
|
||||
ui->loadLastCapture->setText(tr("Load Last Settings - %1").arg(QFileInfo(exe).fileName()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,10 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(roots.size() == 1 && roots[0]->file.filename == "")
|
||||
{
|
||||
normPath.insert(0, QLatin1Char('/'));
|
||||
}
|
||||
|
||||
// normPath is now of the form /subdir1/subdir2/subdir3/...
|
||||
// with ret pointing to the root directory (trivial on unix)
|
||||
@@ -476,6 +480,7 @@ private:
|
||||
child->parent = node;
|
||||
child->parentIndex = i;
|
||||
child->file = sortedFiles[i];
|
||||
child->populated = !(child->file.flags & PathProperty::Directory);
|
||||
node->children.push_back(child);
|
||||
}
|
||||
});
|
||||
@@ -604,6 +609,8 @@ VirtualFileDialog::VirtualFileDialog(ICaptureContext &ctx, QString initialDirect
|
||||
|
||||
QObject::connect(ui->fileList->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
&VirtualFileDialog::fileList_selectionChanged);
|
||||
QObject::connect(ui->dirList->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
&VirtualFileDialog::dirList_selectionChanged);
|
||||
}
|
||||
|
||||
VirtualFileDialog::~VirtualFileDialog()
|
||||
@@ -712,6 +719,14 @@ void VirtualFileDialog::on_dirList_clicked(const QModelIndex &index)
|
||||
changeCurrentDir(m_DirProxy->mapToSource(index));
|
||||
}
|
||||
|
||||
void VirtualFileDialog::dirList_selectionChanged(const QItemSelection &selected,
|
||||
const QItemSelection &deselected)
|
||||
{
|
||||
QModelIndexList indices = selected.indexes();
|
||||
if(indices.count() >= 1)
|
||||
on_dirList_clicked(indices[0]);
|
||||
}
|
||||
|
||||
void VirtualFileDialog::on_fileList_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
bool isDir = m_FileProxy->data(index, RemoteFileModel::FileIsDirRole).toBool();
|
||||
|
||||
@@ -63,6 +63,7 @@ private slots:
|
||||
void on_upFolder_clicked();
|
||||
|
||||
// manual slots
|
||||
void dirList_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void fileList_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
|
||||
private:
|
||||
|
||||
@@ -176,7 +176,7 @@ int GetCurrentPID(const std::string &deviceID, const std::string &packageName)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExecuteResult StartAndroidPackageForCapture(const char *host, const char *package,
|
||||
ExecuteResult StartAndroidPackageForCapture(const char *host, const char *packageAndActivity,
|
||||
const char *intentArgs, const CaptureOptions &opts)
|
||||
{
|
||||
int index = 0;
|
||||
@@ -187,10 +187,14 @@ ExecuteResult StartAndroidPackageForCapture(const char *host, const char *packag
|
||||
ret.status = ReplayStatus::UnknownError;
|
||||
ret.ident = RenderDoc_FirstTargetControlPort + RenderDoc_AndroidPortOffset * (index + 1);
|
||||
|
||||
std::string packageName = get_basename(std::string(package)); // Remove leading '/' if any
|
||||
std::string packageName = GetPackageName(packageAndActivity); // Remove leading '/' if any
|
||||
|
||||
// adb shell cmd package resolve-activity -c android.intent.category.LAUNCHER com.jake.cube1
|
||||
std::string activityName = GetDefaultActivityForPackage(deviceID, packageName);
|
||||
std::string activityName = GetActivityName(packageAndActivity);
|
||||
|
||||
// if the activity name isn't specified, get the default one
|
||||
if(activityName.empty() || activityName == "#DefaultActivity")
|
||||
activityName = GetDefaultActivityForPackage(deviceID, packageName);
|
||||
|
||||
uint16_t jdwpPort = GetJdwpPort();
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
namespace Android
|
||||
{
|
||||
bool IsHostADB(const char *hostname);
|
||||
ExecuteResult StartAndroidPackageForCapture(const char *host, const char *package,
|
||||
std::string GetPackageName(const std::string &packageAndActivity);
|
||||
std::string GetActivityName(const std::string &packageAndActivity);
|
||||
ExecuteResult StartAndroidPackageForCapture(const char *host, const char *packageAndActivity,
|
||||
const char *intentArgs, const CaptureOptions &opts);
|
||||
void ResetCaptureSettings(const std::string &deviceID);
|
||||
void ExtractDeviceIDAndIndex(const std::string &hostname, int &index, std::string &deviceID);
|
||||
|
||||
@@ -523,9 +523,8 @@ bool IsDebuggable(const std::string &deviceID, const std::string &packageName)
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const char *hostname,
|
||||
const char *packageName,
|
||||
AndroidFlags *flags)
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(
|
||||
const char *hostname, const char *packageAndActivity, AndroidFlags *flags)
|
||||
{
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
@@ -534,13 +533,13 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const c
|
||||
// Reset the flags each time we check
|
||||
*flags = AndroidFlags::NoFlags;
|
||||
|
||||
if(Android::IsDebuggable(deviceID, get_basename(std::string(packageName))))
|
||||
if(Android::IsDebuggable(deviceID, Android::GetPackageName(packageAndActivity)))
|
||||
{
|
||||
*flags |= AndroidFlags::Debuggable;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCLOG("%s is not debuggable", packageName);
|
||||
RDCLOG("%s is not debuggable", packageAndActivity);
|
||||
}
|
||||
|
||||
if(Android::HasRootAccess(deviceID))
|
||||
@@ -553,10 +552,11 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(const c
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API AndroidFlags RENDERDOC_CC RENDERDOC_MakeDebuggablePackage(
|
||||
const char *hostname, const char *packageName, RENDERDOC_ProgressCallback progress)
|
||||
const char *hostname, const char *packageAndActivity, RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
std::string package = Android::GetPackageName(packageAndActivity);
|
||||
|
||||
Process::ProcessResult result = {};
|
||||
std::string package(get_basename(std::string(packageName)));
|
||||
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
@@ -629,17 +629,17 @@ extern "C" RENDERDOC_API AndroidFlags RENDERDOC_CC RENDERDOC_MakeDebuggablePacka
|
||||
|
||||
progress(0.525f);
|
||||
|
||||
if(!Android::UninstallOriginalAPK(deviceID, packageName, tmpDir))
|
||||
if(!Android::UninstallOriginalAPK(deviceID, package, tmpDir))
|
||||
return AndroidFlags::RepackagingAPKFailure;
|
||||
|
||||
progress(0.6f);
|
||||
|
||||
if(!Android::ReinstallPatchedAPK(deviceID, alignedAPK, abi, packageName, tmpDir))
|
||||
if(!Android::ReinstallPatchedAPK(deviceID, alignedAPK, abi, package, tmpDir))
|
||||
return AndroidFlags::RepackagingAPKFailure;
|
||||
|
||||
progress(0.95f);
|
||||
|
||||
if(!Android::IsDebuggable(deviceID, packageName))
|
||||
if(!Android::IsDebuggable(deviceID, package))
|
||||
return AndroidFlags::ManifestPatchFailure;
|
||||
|
||||
progress(1.0f);
|
||||
|
||||
@@ -59,6 +59,40 @@ void ExtractDeviceIDAndIndex(const std::string &hostname, int &index, std::strin
|
||||
deviceID = c;
|
||||
}
|
||||
|
||||
std::string GetPackageName(const std::string &packageAndActivity)
|
||||
{
|
||||
if(packageAndActivity.empty())
|
||||
return "";
|
||||
|
||||
size_t start = 0;
|
||||
if(packageAndActivity[0] == '/')
|
||||
start++;
|
||||
|
||||
size_t activitySep = packageAndActivity.find('/', start);
|
||||
|
||||
if(activitySep == std::string::npos)
|
||||
return packageAndActivity.substr(start);
|
||||
|
||||
return packageAndActivity.substr(start, activitySep - start);
|
||||
}
|
||||
|
||||
std::string GetActivityName(const std::string &packageAndActivity)
|
||||
{
|
||||
if(packageAndActivity.empty())
|
||||
return "";
|
||||
|
||||
size_t start = 0;
|
||||
if(packageAndActivity[0] == '/')
|
||||
start++;
|
||||
|
||||
size_t activitySep = packageAndActivity.find('/', start);
|
||||
|
||||
if(activitySep == std::string::npos)
|
||||
return "";
|
||||
|
||||
return packageAndActivity.substr(activitySep + 1);
|
||||
}
|
||||
|
||||
ABI GetABI(const std::string &abiName)
|
||||
{
|
||||
if(abiName == "armeabi-v7a")
|
||||
|
||||
@@ -2367,13 +2367,12 @@ 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,
|
||||
const char *packageName,
|
||||
AndroidFlags *flags);
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(
|
||||
const char *hostname, const char *packageAndActivity, AndroidFlags *flags);
|
||||
|
||||
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);
|
||||
const char *hostname, const char *packageAndActivity, RENDERDOC_ProgressCallback progress);
|
||||
|
||||
DOCUMENT("Internal function that runs unit tests.");
|
||||
extern "C" RENDERDOC_API int RENDERDOC_CC RENDERDOC_RunUnitTests(const rdcstr &command,
|
||||
|
||||
@@ -1197,33 +1197,133 @@ public:
|
||||
std::string deviceID;
|
||||
Android::ExtractDeviceIDAndIndex(m_hostname, index, deviceID);
|
||||
|
||||
std::string adbStdout =
|
||||
Android::adbExecCommand(deviceID, "shell pm list packages -3").strStdout;
|
||||
|
||||
std::istringstream stdoutStream(adbStdout);
|
||||
std::string line;
|
||||
std::vector<PathEntry> packages;
|
||||
while(getline(stdoutStream, line))
|
||||
if(path[0] == 0 || (path[0] == '/' && path[1] == 0))
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
split(line, tokens, ':');
|
||||
if(tokens.size() == 2 && tokens[0] == "package")
|
||||
{
|
||||
PathEntry package;
|
||||
package.filename = trim(tokens[1]);
|
||||
package.size = 0;
|
||||
package.lastmod = 0;
|
||||
package.flags = PathProperty::Executable;
|
||||
SCOPED_TIMER("Fetching android packages and activities");
|
||||
|
||||
std::string adbStdout =
|
||||
Android::adbExecCommand(deviceID, "shell pm list packages -3").strStdout;
|
||||
|
||||
std::vector<std::string> lines;
|
||||
split(adbStdout, lines, '\n');
|
||||
|
||||
std::vector<PathEntry> packages;
|
||||
for(const std::string &line : lines)
|
||||
{
|
||||
// hide our own internal packages
|
||||
if(strstr(package.filename.c_str(), "org.renderdoc."))
|
||||
if(strstr(line.c_str(), "package:org.renderdoc."))
|
||||
continue;
|
||||
|
||||
packages.push_back(package);
|
||||
}
|
||||
}
|
||||
if(!strncmp(line.c_str(), "package:", 8))
|
||||
{
|
||||
PathEntry pkg;
|
||||
pkg.filename = trim(line.substr(8));
|
||||
pkg.size = 0;
|
||||
pkg.lastmod = 0;
|
||||
pkg.flags = PathProperty::Directory;
|
||||
|
||||
return packages;
|
||||
packages.push_back(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
adbStdout = Android::adbExecCommand(deviceID, "shell dumpsys package").strStdout;
|
||||
|
||||
split(adbStdout, lines, '\n');
|
||||
|
||||
for(const std::string &line : lines)
|
||||
{
|
||||
// quick check, look for a /
|
||||
if(line.find('/') == std::string::npos)
|
||||
continue;
|
||||
|
||||
// line should be something like: ' 78f9sba com.package.name/.NameOfActivity .....'
|
||||
|
||||
const char *c = line.c_str();
|
||||
|
||||
// expect whitespace
|
||||
while(*c && isspace(*c))
|
||||
c++;
|
||||
|
||||
// expect hex
|
||||
while(*c && ((*c >= '0' && *c <= '9') || (*c >= 'a' && *c <= 'f')))
|
||||
c++;
|
||||
|
||||
// expect space
|
||||
if(*c != ' ')
|
||||
continue;
|
||||
|
||||
c++;
|
||||
|
||||
// expect the package now. Search to see if it's one of the ones we listed above
|
||||
std::string package;
|
||||
|
||||
for(const PathEntry &p : packages)
|
||||
if(!strncmp(c, p.filename.c_str(), p.filename.size()))
|
||||
package = p.filename;
|
||||
|
||||
// didn't find a matching package
|
||||
if(package.empty())
|
||||
continue;
|
||||
|
||||
c += package.size();
|
||||
|
||||
// expect a /
|
||||
if(*c != '/')
|
||||
continue;
|
||||
|
||||
c++;
|
||||
|
||||
const char *end = strchr(c, ' ');
|
||||
|
||||
if(end == NULL)
|
||||
end = c + strlen(c);
|
||||
|
||||
while(isspace(*(end - 1)))
|
||||
end--;
|
||||
|
||||
m_AndroidActivities.insert({package, rdcstr(c, end - c)});
|
||||
}
|
||||
|
||||
return packages;
|
||||
}
|
||||
else
|
||||
{
|
||||
rdcstr package = path;
|
||||
|
||||
if(!package.empty() && package[0] == '/')
|
||||
package.erase(0);
|
||||
|
||||
std::vector<PathEntry> activities;
|
||||
|
||||
for(const Activity &act : m_AndroidActivities)
|
||||
{
|
||||
if(act.package == package)
|
||||
{
|
||||
PathEntry activity;
|
||||
if(act.activity[0] == '.')
|
||||
activity.filename = package + act.activity;
|
||||
else
|
||||
activity.filename = act.activity;
|
||||
activity.size = 0;
|
||||
activity.lastmod = 0;
|
||||
activity.flags = PathProperty::Executable;
|
||||
activities.push_back(activity);
|
||||
}
|
||||
}
|
||||
|
||||
PathEntry defaultActivity;
|
||||
defaultActivity.filename = "#DefaultActivity";
|
||||
defaultActivity.size = 0;
|
||||
defaultActivity.lastmod = 0;
|
||||
defaultActivity.flags = PathProperty::Executable;
|
||||
|
||||
// if there's only one activity listed, assume it's the default and don't add a virtual
|
||||
// entry
|
||||
if(activities.size() != 1)
|
||||
activities.push_back(defaultActivity);
|
||||
|
||||
return activities;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1859,6 +1959,21 @@ private:
|
||||
Android::LogcatThread *m_LogcatThread;
|
||||
|
||||
std::vector<rdcpair<RDCDriver, std::string> > m_Proxies;
|
||||
|
||||
struct Activity
|
||||
{
|
||||
rdcstr package;
|
||||
rdcstr activity;
|
||||
|
||||
bool operator<(const Activity &o) const
|
||||
{
|
||||
if(package != o.package)
|
||||
return package < o.package;
|
||||
return activity < o.activity;
|
||||
}
|
||||
};
|
||||
|
||||
std::set<Activity> m_AndroidActivities;
|
||||
};
|
||||
|
||||
extern "C" RENDERDOC_API ReplayStatus RENDERDOC_CC
|
||||
|
||||
Reference in New Issue
Block a user