Split out handling of android tools: locating&precedence, executing, etc

This commit is contained in:
baldurk
2018-01-26 15:56:31 +00:00
parent ae7300e524
commit 1be3e8bfac
7 changed files with 356 additions and 269 deletions
+2
View File
@@ -90,7 +90,9 @@ set(sources
core/replay_proxy.cpp
core/replay_proxy.h
android/android.cpp
android/android_tools.cpp
android/android.h
android/android_utils.h
core/plugins.cpp
core/plugins.h
core/resource_manager.cpp
+3 -268
View File
@@ -27,6 +27,7 @@
#include "api/replay/version.h"
#include "core/core.h"
#include "strings/string_utils.h"
#include "android_utils.h"
// we use GIT_COMMIT_HASH here instead of GitVersionHash since the value is actually only used on
// android - where GIT_COMMIT_HASH is available globally. We need to have it available in a static
@@ -38,247 +39,10 @@
extern "C" RENDERDOC_API const char RENDERDOC_Version_Tag_String[] =
"RenderDoc_build_version: " FULL_VERSION_STRING " from git commit " GIT_COMMIT_HASH;
static const char keystoreName[] = "renderdoc.keystore";
namespace Android
{
enum class ToolDir
{
None,
Java,
BuildTools,
BuildToolsLib,
PlatformTools,
};
static const char keystoreName[] = "renderdoc.keystore";
bool toolExists(const std::string &path)
{
if(path.empty())
return false;
return FileIO::exists(path.c_str()) || FileIO::exists((path + ".exe").c_str());
}
std::string getToolInSDK(ToolDir subdir, const std::string &jdkroot, const std::string &sdkroot,
const std::string &toolname)
{
std::string toolpath;
switch(subdir)
{
case ToolDir::None:
{
// This indicates the file is not a standard tool and will not exist anywhere but our
// distributed folder.
break;
}
case ToolDir::Java:
{
// if no path is configured, abort
if(jdkroot.empty())
break;
toolpath = jdkroot + "/bin/" + toolname;
if(toolExists(toolpath))
return toolpath;
break;
}
case ToolDir::BuildTools:
case ToolDir::BuildToolsLib:
case ToolDir::PlatformTools:
{
// if no path is configured, abort
if(sdkroot.empty())
break;
// if it's in platform tools it's easy, just concatenate the path
if(subdir == ToolDir::PlatformTools)
{
toolpath = sdkroot + "/platform-tools/" + toolname;
}
else
{
// otherwise we need to find the build-tools versioned folder
toolpath = sdkroot + "/build-tools/";
std::vector<PathEntry> paths = FileIO::GetFilesInDirectory(toolpath.c_str());
if(paths.empty())
break;
uint32_t bestversion = 0;
std::string bestpath;
for(const PathEntry &path : paths)
{
// skip non-directories
if(!(path.flags & PathProperty::Directory))
continue;
uint32_t version = 0;
bool valid = true;
for(char c : path.filename)
{
// add digits to the version
if(c >= '0' && c <= '9')
{
int digit = int(c) - int('0');
version *= 10;
version += digit;
continue;
}
// ignore .s
if(c == '.')
continue;
// if any char is not in [.0-9] then this filename is invalid
valid = false;
break;
}
// skip non-valid directories
if(!valid)
continue;
// if this directory is a higher version, prefer it
if(version > bestversion)
{
bestversion = version;
bestpath = path.filename;
}
}
// if we didn't find a version at all, abort
if(bestversion == 0)
break;
toolpath += bestpath + "/";
if(subdir == ToolDir::BuildToolsLib)
toolpath += "lib/";
toolpath += toolname;
}
if(toolExists(toolpath))
return toolpath;
break;
}
}
return "";
}
struct ToolPathCache
{
std::string sdk, jdk;
std::map<std::string, std::string> paths;
} cache;
std::string getToolPath(ToolDir subdir, const std::string &toolname, bool checkExist)
{
// search path for tools:
// 1. First look relative to the configured paths, these come from the user manually setting them
// so they always have priority.
// 2. Next if those paths don't exist or the tool isn't found, we search relative to our
// executable looking for an android/ subfolder, and look for the tool in there.
// 3. If we still don't have that (most likely because it's a local build from a git clone and not
// a distributed build with the tools available) then we fall back to trying to auto-locate it.
// - First check if the tool is in the path, assuming the user configured it to their system.
// - Otherwise check environment variables or default locations
std::string sdk = RenderDoc::Inst().GetConfigSetting("androidSDKPath");
std::string jdk = RenderDoc::Inst().GetConfigSetting("androidJDKPath");
// invalidate the cache when these settings change
if(sdk != cache.sdk || jdk != cache.jdk)
{
cache.paths.clear();
cache.sdk = sdk;
cache.jdk = jdk;
}
// if we have the path cached and it's still valid, return it
if(toolExists(cache.paths[toolname]))
return cache.paths[toolname];
std::string &toolpath = cache.paths[toolname];
// first try according to the configured paths
toolpath = getToolInSDK(subdir, jdk, sdk, toolname);
if(toolExists(toolpath))
return toolpath;
// next try to locate it in our own distributed android subfolder
{
std::string exepath;
FileIO::GetExecutableFilename(exepath);
std::string exedir = dirname(FileIO::GetFullPathname(exepath));
toolpath = exedir + "/android/" + toolname;
if(toolExists(toolpath))
return toolpath;
}
// need to try to auto-guess the tool's location
// first try in PATH
if(subdir != ToolDir::None)
{
toolpath = FileIO::FindFileInPath(toolname);
if(toolExists(toolpath))
return toolpath;
// if the tool name contains a .jar then try stripping that and look for the non-.jar version in
// the PATH.
if(toolname.find(".jar") != std::string::npos)
{
toolpath = toolname;
toolpath.erase(toolpath.rfind(".jar"), 4);
toolpath = FileIO::FindFileInPath(toolpath);
if(toolExists(toolpath))
return toolpath;
}
}
// now try to find it based on heuristics/environment variables
const char *env = Process::GetEnvVariable("JAVA_HOME");
jdk = env ? env : "";
env = Process::GetEnvVariable("ANDROID_HOME");
sdk = env ? env : "";
if(sdk.empty() || !FileIO::exists(sdk.c_str()))
{
env = Process::GetEnvVariable("ANDROID_SDK_ROOT");
sdk = env ? env : "";
}
if(sdk.empty() || !FileIO::exists(sdk.c_str()))
{
env = Process::GetEnvVariable("ANDROID_SDK");
sdk = env ? env : "";
}
// maybe in future we can try to search in common install locations.
toolpath = getToolInSDK(subdir, jdk, sdk, toolname);
if(toolExists(toolpath))
return toolpath;
toolpath = "";
// if we're checking for existence, we have failed so return empty string.
if(checkExist)
return toolpath;
// otherwise we at least return the tool name so that there's something to try and run
return toolname;
}
bool IsHostADB(const char *hostname)
{
return !strncmp(hostname, "adb:", 4);
@@ -305,35 +69,6 @@ void extractDeviceIDAndIndex(const string &hostname, int &index, string &deviceI
deviceID = c;
}
Process::ProcessResult execScript(const string &script, const string &args,
const string &workDir = ".")
{
RDCLOG("SCRIPT: %s", script.c_str());
Process::ProcessResult result;
Process::LaunchScript(script.c_str(), workDir.c_str(), args.c_str(), true, &result);
return result;
}
Process::ProcessResult execCommand(const string &exe, const string &args,
const string &workDir = ".")
{
RDCLOG("COMMAND: %s '%s'", exe.c_str(), args.c_str());
Process::ProcessResult result;
Process::LaunchProcess(exe.c_str(), workDir.c_str(), args.c_str(), true, &result);
return result;
}
Process::ProcessResult adbExecCommand(const string &device, const string &args, const string &workDir)
{
std::string adb = getToolPath(ToolDir::PlatformTools, "adb", false);
Process::ProcessResult result;
string deviceArgs;
if(device.empty())
deviceArgs = args;
else
deviceArgs = StringFormat::Fmt("-s %s %s", device.c_str(), args.c_str());
return execCommand(adb, deviceArgs, workDir);
}
string adbGetDeviceList()
{
return adbExecCommand("", "devices").strStdout;
+4 -1
View File
@@ -22,14 +22,17 @@
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <string>
#include "os/os_specific.h"
// public interface, for other non-android parts of the code
namespace Android
{
bool IsHostADB(const char *hostname);
uint32_t StartAndroidPackageForCapture(const char *host, const char *package);
void extractDeviceIDAndIndex(const std::string &hostname, int &index, std::string &deviceID);
Process::ProcessResult adbExecCommand(const std::string &deviceID, const std::string &args,
const string &workDir = ".");
void extractDeviceIDAndIndex(const std::string &hostname, int &index, std::string &deviceID);
};
+290
View File
@@ -0,0 +1,290 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2018 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "core/core.h"
#include "strings/string_utils.h"
#include "android_utils.h"
namespace Android
{
bool toolExists(const std::string &path)
{
if(path.empty())
return false;
return FileIO::exists(path.c_str()) || FileIO::exists((path + ".exe").c_str());
}
std::string getToolInSDK(ToolDir subdir, const std::string &jdkroot, const std::string &sdkroot,
const std::string &toolname)
{
std::string toolpath;
switch(subdir)
{
case ToolDir::None:
{
// This indicates the file is not a standard tool and will not exist anywhere but our
// distributed folder.
break;
}
case ToolDir::Java:
{
// if no path is configured, abort
if(jdkroot.empty())
break;
toolpath = jdkroot + "/bin/" + toolname;
if(toolExists(toolpath))
return toolpath;
break;
}
case ToolDir::BuildTools:
case ToolDir::BuildToolsLib:
case ToolDir::PlatformTools:
{
// if no path is configured, abort
if(sdkroot.empty())
break;
// if it's in platform tools it's easy, just concatenate the path
if(subdir == ToolDir::PlatformTools)
{
toolpath = sdkroot + "/platform-tools/" + toolname;
}
else
{
// otherwise we need to find the build-tools versioned folder
toolpath = sdkroot + "/build-tools/";
std::vector<PathEntry> paths = FileIO::GetFilesInDirectory(toolpath.c_str());
if(paths.empty())
break;
uint32_t bestversion = 0;
std::string bestpath;
for(const PathEntry &path : paths)
{
// skip non-directories
if(!(path.flags & PathProperty::Directory))
continue;
uint32_t version = 0;
bool valid = true;
for(char c : path.filename)
{
// add digits to the version
if(c >= '0' && c <= '9')
{
int digit = int(c) - int('0');
version *= 10;
version += digit;
continue;
}
// ignore .s
if(c == '.')
continue;
// if any char is not in [.0-9] then this filename is invalid
valid = false;
break;
}
// skip non-valid directories
if(!valid)
continue;
// if this directory is a higher version, prefer it
if(version > bestversion)
{
bestversion = version;
bestpath = path.filename;
}
}
// if we didn't find a version at all, abort
if(bestversion == 0)
break;
toolpath += bestpath + "/";
if(subdir == ToolDir::BuildToolsLib)
toolpath += "lib/";
toolpath += toolname;
}
if(toolExists(toolpath))
return toolpath;
break;
}
}
return "";
}
struct ToolPathCache
{
std::string sdk, jdk;
std::map<std::string, std::string> paths;
} cache;
std::string getToolPath(ToolDir subdir, const std::string &toolname, bool checkExist)
{
// search path for tools:
// 1. First look relative to the configured paths, these come from the user manually setting them
// so they always have priority.
// 2. Next if those paths don't exist or the tool isn't found, we search relative to our
// executable looking for an android/ subfolder, and look for the tool in there.
// 3. If we still don't have that (most likely because it's a local build from a git clone and not
// a distributed build with the tools available) then we fall back to trying to auto-locate it.
// - First check if the tool is in the path, assuming the user configured it to their system.
// - Otherwise check environment variables or default locations
std::string sdk = RenderDoc::Inst().GetConfigSetting("androidSDKPath");
std::string jdk = RenderDoc::Inst().GetConfigSetting("androidJDKPath");
// invalidate the cache when these settings change
if(sdk != cache.sdk || jdk != cache.jdk)
{
cache.paths.clear();
cache.sdk = sdk;
cache.jdk = jdk;
}
// if we have the path cached and it's still valid, return it
if(toolExists(cache.paths[toolname]))
return cache.paths[toolname];
std::string &toolpath = cache.paths[toolname];
// first try according to the configured paths
toolpath = getToolInSDK(subdir, jdk, sdk, toolname);
if(toolExists(toolpath))
return toolpath;
// next try to locate it in our own distributed android subfolder
{
std::string exepath;
FileIO::GetExecutableFilename(exepath);
std::string exedir = dirname(FileIO::GetFullPathname(exepath));
toolpath = exedir + "/android/" + toolname;
if(toolExists(toolpath))
return toolpath;
}
// need to try to auto-guess the tool's location
// first try in PATH
if(subdir != ToolDir::None)
{
toolpath = FileIO::FindFileInPath(toolname);
if(toolExists(toolpath))
return toolpath;
// if the tool name contains a .jar then try stripping that and look for the non-.jar version in
// the PATH.
if(toolname.find(".jar") != std::string::npos)
{
toolpath = toolname;
toolpath.erase(toolpath.rfind(".jar"), 4);
toolpath = FileIO::FindFileInPath(toolpath);
if(toolExists(toolpath))
return toolpath;
}
}
// now try to find it based on heuristics/environment variables
const char *env = Process::GetEnvVariable("JAVA_HOME");
jdk = env ? env : "";
env = Process::GetEnvVariable("ANDROID_HOME");
sdk = env ? env : "";
if(sdk.empty() || !FileIO::exists(sdk.c_str()))
{
env = Process::GetEnvVariable("ANDROID_SDK_ROOT");
sdk = env ? env : "";
}
if(sdk.empty() || !FileIO::exists(sdk.c_str()))
{
env = Process::GetEnvVariable("ANDROID_SDK");
sdk = env ? env : "";
}
// maybe in future we can try to search in common install locations.
toolpath = getToolInSDK(subdir, jdk, sdk, toolname);
if(toolExists(toolpath))
return toolpath;
toolpath = "";
// if we're checking for existence, we have failed so return empty string.
if(checkExist)
return toolpath;
// otherwise we at least return the tool name so that there's something to try and run
return toolname;
}
Process::ProcessResult execScript(const std::string &script, const std::string &args,
const std::string &workDir)
{
RDCLOG("SCRIPT: %s", script.c_str());
Process::ProcessResult result;
Process::LaunchScript(script.c_str(), workDir.c_str(), args.c_str(), true, &result);
return result;
}
Process::ProcessResult execCommand(const std::string &exe, const std::string &args,
const std::string &workDir)
{
RDCLOG("COMMAND: %s '%s'", exe.c_str(), args.c_str());
Process::ProcessResult result;
Process::LaunchProcess(exe.c_str(), workDir.c_str(), args.c_str(), true, &result);
return result;
}
Process::ProcessResult adbExecCommand(const std::string &device, const std::string &args,
const std::string &workDir)
{
std::string adb = getToolPath(ToolDir::PlatformTools, "adb", false);
Process::ProcessResult result;
std::string deviceArgs;
if(device.empty())
deviceArgs = args;
else
deviceArgs = StringFormat::Fmt("-s %s %s", device.c_str(), args.c_str());
return execCommand(adb, deviceArgs, workDir);
}
};
+49
View File
@@ -0,0 +1,49 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include "android.h"
// internal functions, shouldn't be used outside the android implementation - anything public goes
// in android.h
namespace Android
{
Process::ProcessResult execScript(const string &script, const string &args,
const string &workDir = ".");
Process::ProcessResult execCommand(const string &exe, const string &args,
const string &workDir = ".");
enum class ToolDir
{
None,
Java,
BuildTools,
BuildToolsLib,
PlatformTools,
};
std::string getToolPath(ToolDir subdir, const std::string &toolname, bool checkExist);
bool toolExists(const std::string &path);
};
+2
View File
@@ -133,6 +133,7 @@
<ClInclude Include="3rdparty\zstd\zstd_opt.h" />
<ClInclude Include="3rdparty\zstd\zstd.h" />
<ClInclude Include="android\android.h" />
<ClInclude Include="android\android_utils.h" />
<ClInclude Include="api\app\renderdoc_app.h" />
<ClInclude Include="api\replay\basic_types.h" />
<ClInclude Include="api\replay\capture_options.h" />
@@ -306,6 +307,7 @@
</ForcedIncludeFiles>
</ClCompile>
<ClCompile Include="android\android.cpp" />
<ClCompile Include="android\android_tools.cpp" />
<ClCompile Include="common\common.cpp" />
<ClCompile Include="common\dds_readwrite.cpp" />
<ClCompile Include="core\core.cpp" />
+6
View File
@@ -378,6 +378,9 @@
<ClInclude Include="android\android.h">
<Filter>Android</Filter>
</ClInclude>
<ClInclude Include="android\android_utils.h">
<Filter>Android</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="maths\camera.cpp">
@@ -653,6 +656,9 @@
<ClCompile Include="android\android.cpp">
<Filter>Android</Filter>
</ClCompile>
<ClCompile Include="android\android_tools.cpp">
<Filter>Android</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="os\win32\comexport.def">