100e305d2STamas Berghammer //===-- PlatformAndroid.cpp -------------------------------------*- C++ -*-===//
200e305d2STamas Berghammer //
300e305d2STamas Berghammer //                     The LLVM Compiler Infrastructure
400e305d2STamas Berghammer //
500e305d2STamas Berghammer // This file is distributed under the University of Illinois Open Source
600e305d2STamas Berghammer // License. See LICENSE.TXT for details.
700e305d2STamas Berghammer //
800e305d2STamas Berghammer //===----------------------------------------------------------------------===//
900e305d2STamas Berghammer 
1000e305d2STamas Berghammer // C Includes
1100e305d2STamas Berghammer // C++ Includes
1200e305d2STamas Berghammer // Other libraries and framework includes
13b9c1b51eSKate Stone #include "Utility/UriParser.h"
1400e305d2STamas Berghammer #include "lldb/Core/Log.h"
15ec3f92a5STamas Berghammer #include "lldb/Core/Module.h"
1600e305d2STamas Berghammer #include "lldb/Core/PluginManager.h"
173cb132a0STamas Berghammer #include "lldb/Core/Scalar.h"
18ec3f92a5STamas Berghammer #include "lldb/Core/Section.h"
193cb132a0STamas Berghammer #include "lldb/Core/ValueObject.h"
201c6a1ea9STamas Berghammer #include "lldb/Host/HostInfo.h"
211d0d90b9STamas Berghammer #include "lldb/Host/StringConvert.h"
2200e305d2STamas Berghammer 
2300e305d2STamas Berghammer // Project includes
246f001068SOleksiy Vyalov #include "AdbClient.h"
2500e305d2STamas Berghammer #include "PlatformAndroid.h"
2600e305d2STamas Berghammer #include "PlatformAndroidRemoteGDBServer.h"
2700e305d2STamas Berghammer 
2800e305d2STamas Berghammer using namespace lldb;
2900e305d2STamas Berghammer using namespace lldb_private;
30db264a6dSTamas Berghammer using namespace lldb_private::platform_android;
3100e305d2STamas Berghammer 
3200e305d2STamas Berghammer static uint32_t g_initialize_count = 0;
33b9c1b51eSKate Stone static const unsigned int g_android_default_cache_size =
34b9c1b51eSKate Stone     2048; // Fits inside 4k adb packet.
3500e305d2STamas Berghammer 
36b9c1b51eSKate Stone void PlatformAndroid::Initialize() {
373c4f89d7STamas Berghammer   PlatformLinux::Initialize();
383c4f89d7STamas Berghammer 
39b9c1b51eSKate Stone   if (g_initialize_count++ == 0) {
401c6a1ea9STamas Berghammer #if defined(__ANDROID__)
411c6a1ea9STamas Berghammer     PlatformSP default_platform_sp(new PlatformAndroid(true));
421c6a1ea9STamas Berghammer     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
431c6a1ea9STamas Berghammer     Platform::SetHostPlatform(default_platform_sp);
441c6a1ea9STamas Berghammer #endif
45b9c1b51eSKate Stone     PluginManager::RegisterPlugin(
46b9c1b51eSKate Stone         PlatformAndroid::GetPluginNameStatic(false),
471c6a1ea9STamas Berghammer         PlatformAndroid::GetPluginDescriptionStatic(false),
4800e305d2STamas Berghammer         PlatformAndroid::CreateInstance);
4900e305d2STamas Berghammer   }
5000e305d2STamas Berghammer }
5100e305d2STamas Berghammer 
52b9c1b51eSKate Stone void PlatformAndroid::Terminate() {
53b9c1b51eSKate Stone   if (g_initialize_count > 0) {
54b9c1b51eSKate Stone     if (--g_initialize_count == 0) {
5500e305d2STamas Berghammer       PluginManager::UnregisterPlugin(PlatformAndroid::CreateInstance);
5600e305d2STamas Berghammer     }
5700e305d2STamas Berghammer   }
583c4f89d7STamas Berghammer 
593c4f89d7STamas Berghammer   PlatformLinux::Terminate();
6000e305d2STamas Berghammer }
6100e305d2STamas Berghammer 
62b9c1b51eSKate Stone PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) {
63db264a6dSTamas Berghammer   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
64b9c1b51eSKate Stone   if (log) {
6500e305d2STamas Berghammer     const char *arch_name;
6600e305d2STamas Berghammer     if (arch && arch->GetArchitectureName())
6700e305d2STamas Berghammer       arch_name = arch->GetArchitectureName();
6800e305d2STamas Berghammer     else
6900e305d2STamas Berghammer       arch_name = "<null>";
7000e305d2STamas Berghammer 
71b9c1b51eSKate Stone     const char *triple_cstr =
72b9c1b51eSKate Stone         arch ? arch->GetTriple().getTriple().c_str() : "<null>";
7300e305d2STamas Berghammer 
74b9c1b51eSKate Stone     log->Printf("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__,
75b9c1b51eSKate Stone                 force ? "true" : "false", arch_name, triple_cstr);
7600e305d2STamas Berghammer   }
7700e305d2STamas Berghammer 
7800e305d2STamas Berghammer   bool create = force;
79b9c1b51eSKate Stone   if (create == false && arch && arch->IsValid()) {
8000e305d2STamas Berghammer     const llvm::Triple &triple = arch->GetTriple();
81b9c1b51eSKate Stone     switch (triple.getVendor()) {
8200e305d2STamas Berghammer     case llvm::Triple::PC:
8300e305d2STamas Berghammer       create = true;
8400e305d2STamas Berghammer       break;
8500e305d2STamas Berghammer 
8600e305d2STamas Berghammer #if defined(__ANDROID__)
8700e305d2STamas Berghammer     // Only accept "unknown" for the vendor if the host is android and
8800e305d2STamas Berghammer     // it "unknown" wasn't specified (it was just returned because it
8900e305d2STamas Berghammer     // was NOT specified_
9000e305d2STamas Berghammer     case llvm::Triple::VendorType::UnknownVendor:
9100e305d2STamas Berghammer       create = !arch->TripleVendorWasSpecified();
9200e305d2STamas Berghammer       break;
9300e305d2STamas Berghammer #endif
9400e305d2STamas Berghammer     default:
9500e305d2STamas Berghammer       break;
9600e305d2STamas Berghammer     }
9700e305d2STamas Berghammer 
98b9c1b51eSKate Stone     if (create) {
99b9c1b51eSKate Stone       switch (triple.getOS()) {
1001c6a1ea9STamas Berghammer       case llvm::Triple::Android:
10100e305d2STamas Berghammer         break;
10200e305d2STamas Berghammer 
10300e305d2STamas Berghammer #if defined(__ANDROID__)
10400e305d2STamas Berghammer       // Only accept "unknown" for the OS if the host is android and
10500e305d2STamas Berghammer       // it "unknown" wasn't specified (it was just returned because it
10600e305d2STamas Berghammer       // was NOT specified)
10700e305d2STamas Berghammer       case llvm::Triple::OSType::UnknownOS:
10800e305d2STamas Berghammer         create = !arch->TripleOSWasSpecified();
10900e305d2STamas Berghammer         break;
11000e305d2STamas Berghammer #endif
11100e305d2STamas Berghammer       default:
11200e305d2STamas Berghammer         create = false;
11300e305d2STamas Berghammer         break;
11400e305d2STamas Berghammer       }
11500e305d2STamas Berghammer     }
11600e305d2STamas Berghammer   }
11700e305d2STamas Berghammer 
118b9c1b51eSKate Stone   if (create) {
11900e305d2STamas Berghammer     if (log)
120b9c1b51eSKate Stone       log->Printf("PlatformAndroid::%s() creating remote-android platform",
121b9c1b51eSKate Stone                   __FUNCTION__);
1221c6a1ea9STamas Berghammer     return PlatformSP(new PlatformAndroid(false));
12300e305d2STamas Berghammer   }
12400e305d2STamas Berghammer 
12500e305d2STamas Berghammer   if (log)
126b9c1b51eSKate Stone     log->Printf(
127b9c1b51eSKate Stone         "PlatformAndroid::%s() aborting creation of remote-android platform",
128b9c1b51eSKate Stone         __FUNCTION__);
12900e305d2STamas Berghammer 
13000e305d2STamas Berghammer   return PlatformSP();
13100e305d2STamas Berghammer }
13200e305d2STamas Berghammer 
133b9c1b51eSKate Stone PlatformAndroid::PlatformAndroid(bool is_host)
134b9c1b51eSKate Stone     : PlatformLinux(is_host), m_sdk_version(0) {}
13500e305d2STamas Berghammer 
136b9c1b51eSKate Stone PlatformAndroid::~PlatformAndroid() {}
13700e305d2STamas Berghammer 
138b9c1b51eSKate Stone ConstString PlatformAndroid::GetPluginNameStatic(bool is_host) {
139b9c1b51eSKate Stone   if (is_host) {
1401c6a1ea9STamas Berghammer     static ConstString g_host_name(Platform::GetHostPlatformName());
1411c6a1ea9STamas Berghammer     return g_host_name;
142b9c1b51eSKate Stone   } else {
14300e305d2STamas Berghammer     static ConstString g_remote_name("remote-android");
14400e305d2STamas Berghammer     return g_remote_name;
14500e305d2STamas Berghammer   }
1461c6a1ea9STamas Berghammer }
14700e305d2STamas Berghammer 
148b9c1b51eSKate Stone const char *PlatformAndroid::GetPluginDescriptionStatic(bool is_host) {
1491c6a1ea9STamas Berghammer   if (is_host)
1501c6a1ea9STamas Berghammer     return "Local Android user platform plug-in.";
1511c6a1ea9STamas Berghammer   else
15200e305d2STamas Berghammer     return "Remote Android user platform plug-in.";
15300e305d2STamas Berghammer }
15400e305d2STamas Berghammer 
155b9c1b51eSKate Stone ConstString PlatformAndroid::GetPluginName() {
1561c6a1ea9STamas Berghammer   return GetPluginNameStatic(IsHost());
15700e305d2STamas Berghammer }
15800e305d2STamas Berghammer 
159b9c1b51eSKate Stone Error PlatformAndroid::ConnectRemote(Args &args) {
1606f001068SOleksiy Vyalov   m_device_id.clear();
1616f001068SOleksiy Vyalov 
162b9c1b51eSKate Stone   if (IsHost()) {
163b9c1b51eSKate Stone     return Error("can't connect to the host platform '%s', always connected",
164b9c1b51eSKate Stone                  GetPluginName().GetCString());
1651c6a1ea9STamas Berghammer   }
1661c6a1ea9STamas Berghammer 
16700e305d2STamas Berghammer   if (!m_remote_platform_sp)
16800e305d2STamas Berghammer     m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
1696f001068SOleksiy Vyalov 
1703ea689b3SChaoren Lin   int port;
1713ea689b3SChaoren Lin   std::string scheme, host, path;
1723ea689b3SChaoren Lin   const char *url = args.GetArgumentAtIndex(0);
1733ea689b3SChaoren Lin   if (!url)
1743ea689b3SChaoren Lin     return Error("URL is null.");
1753ea689b3SChaoren Lin   if (!UriParser::Parse(url, scheme, host, port, path))
1763ea689b3SChaoren Lin     return Error("Invalid URL: %s", url);
177a29d6475SOleksiy Vyalov   if (host != "localhost")
1783ea689b3SChaoren Lin     m_device_id = host;
1793ea689b3SChaoren Lin 
1806f001068SOleksiy Vyalov   auto error = PlatformLinux::ConnectRemote(args);
181b9c1b51eSKate Stone   if (error.Success()) {
182d6a143fcSOleksiy Vyalov     AdbClient adb;
183d6a143fcSOleksiy Vyalov     error = AdbClient::CreateByDeviceID(m_device_id, adb);
1846f001068SOleksiy Vyalov     if (error.Fail())
1856f001068SOleksiy Vyalov       return error;
1866f001068SOleksiy Vyalov 
187d6a143fcSOleksiy Vyalov     m_device_id = adb.GetDeviceID();
1886f001068SOleksiy Vyalov   }
1896f001068SOleksiy Vyalov   return error;
1906f001068SOleksiy Vyalov }
1916f001068SOleksiy Vyalov 
192b9c1b51eSKate Stone Error PlatformAndroid::GetFile(const FileSpec &source,
193b9c1b51eSKate Stone                                const FileSpec &destination) {
194291f59c5SOleksiy Vyalov   if (IsHost() || !m_remote_platform_sp)
1950b5ebef7SOleksiy Vyalov     return PlatformLinux::GetFile(source, destination);
196291f59c5SOleksiy Vyalov 
197b9c1b51eSKate Stone   FileSpec source_spec(source.GetPath(false), false,
198b9c1b51eSKate Stone                        FileSpec::ePathSyntaxPosix);
199372e9067SChaoren Lin   if (source_spec.IsRelative())
200b9c1b51eSKate Stone     source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent(
201b9c1b51eSKate Stone         source_spec.GetCString(false));
202291f59c5SOleksiy Vyalov 
203d6a143fcSOleksiy Vyalov   Error error;
204d6a143fcSOleksiy Vyalov   auto sync_service = GetSyncService(error);
205d6a143fcSOleksiy Vyalov   if (error.Fail())
206d6a143fcSOleksiy Vyalov     return error;
207d6a143fcSOleksiy Vyalov 
208c6ac2e1eSOleksiy Vyalov   uint32_t mode = 0, size = 0, mtime = 0;
209c6ac2e1eSOleksiy Vyalov   error = sync_service->Stat(source_spec, mode, size, mtime);
210c6ac2e1eSOleksiy Vyalov   if (error.Fail())
211c6ac2e1eSOleksiy Vyalov     return error;
212c6ac2e1eSOleksiy Vyalov 
213c6ac2e1eSOleksiy Vyalov   if (mode != 0)
214d6a143fcSOleksiy Vyalov     return sync_service->PullFile(source_spec, destination);
215c6ac2e1eSOleksiy Vyalov 
216c6ac2e1eSOleksiy Vyalov   auto source_file = source_spec.GetCString(false);
217c6ac2e1eSOleksiy Vyalov 
218c6ac2e1eSOleksiy Vyalov   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
219c6ac2e1eSOleksiy Vyalov   if (log)
220b9c1b51eSKate Stone     log->Printf("Got mode == 0 on '%s': try to get file via 'shell cat'",
221b9c1b51eSKate Stone                 source_file);
222c6ac2e1eSOleksiy Vyalov 
223c6ac2e1eSOleksiy Vyalov   if (strchr(source_file, '\'') != nullptr)
224c6ac2e1eSOleksiy Vyalov     return Error("Doesn't support single-quotes in filenames");
225c6ac2e1eSOleksiy Vyalov 
226c6ac2e1eSOleksiy Vyalov   // mode == 0 can signify that adbd cannot access the file
227c6ac2e1eSOleksiy Vyalov   // due security constraints - try "cat ..." as a fallback.
228c6ac2e1eSOleksiy Vyalov   AdbClient adb(m_device_id);
229c6ac2e1eSOleksiy Vyalov 
230c6ac2e1eSOleksiy Vyalov   char cmd[PATH_MAX];
231c6ac2e1eSOleksiy Vyalov   snprintf(cmd, sizeof(cmd), "cat '%s'", source_file);
232c6ac2e1eSOleksiy Vyalov 
233c6ac2e1eSOleksiy Vyalov   return adb.ShellToFile(cmd, 60000 /* ms */, destination);
2340b5ebef7SOleksiy Vyalov }
2350b5ebef7SOleksiy Vyalov 
236b9c1b51eSKate Stone Error PlatformAndroid::PutFile(const FileSpec &source,
237b9c1b51eSKate Stone                                const FileSpec &destination, uint32_t uid,
238b9c1b51eSKate Stone                                uint32_t gid) {
23917701b59SOleksiy Vyalov   if (IsHost() || !m_remote_platform_sp)
24017701b59SOleksiy Vyalov     return PlatformLinux::PutFile(source, destination, uid, gid);
24117701b59SOleksiy Vyalov 
242b9c1b51eSKate Stone   FileSpec destination_spec(destination.GetPath(false), false,
243b9c1b51eSKate Stone                             FileSpec::ePathSyntaxPosix);
244372e9067SChaoren Lin   if (destination_spec.IsRelative())
245b9c1b51eSKate Stone     destination_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent(
246b9c1b51eSKate Stone         destination_spec.GetCString(false));
24717701b59SOleksiy Vyalov 
24862efb1f6SRobert Flack   // TODO: Set correct uid and gid on remote file.
249d6a143fcSOleksiy Vyalov   Error error;
250d6a143fcSOleksiy Vyalov   auto sync_service = GetSyncService(error);
251d6a143fcSOleksiy Vyalov   if (error.Fail())
252d6a143fcSOleksiy Vyalov     return error;
253d6a143fcSOleksiy Vyalov   return sync_service->PushFile(source, destination_spec);
25462efb1f6SRobert Flack }
25562efb1f6SRobert Flack 
256b9c1b51eSKate Stone const char *PlatformAndroid::GetCacheHostname() { return m_device_id.c_str(); }
25709e9079dSOleksiy Vyalov 
258b9c1b51eSKate Stone Error PlatformAndroid::DownloadModuleSlice(const FileSpec &src_file_spec,
25909e9079dSOleksiy Vyalov                                            const uint64_t src_offset,
26009e9079dSOleksiy Vyalov                                            const uint64_t src_size,
261b9c1b51eSKate Stone                                            const FileSpec &dst_file_spec) {
26209e9079dSOleksiy Vyalov   if (src_offset != 0)
26309e9079dSOleksiy Vyalov     return Error("Invalid offset - %" PRIu64, src_offset);
26409e9079dSOleksiy Vyalov 
2650b5ebef7SOleksiy Vyalov   return GetFile(src_file_spec, dst_file_spec);
26609e9079dSOleksiy Vyalov }
2671d0d90b9STamas Berghammer 
268b9c1b51eSKate Stone Error PlatformAndroid::DisconnectRemote() {
2691d0d90b9STamas Berghammer   Error error = PlatformLinux::DisconnectRemote();
270b9c1b51eSKate Stone   if (error.Success()) {
2711d0d90b9STamas Berghammer     m_device_id.clear();
2721d0d90b9STamas Berghammer     m_sdk_version = 0;
2731d0d90b9STamas Berghammer   }
2741d0d90b9STamas Berghammer   return error;
2751d0d90b9STamas Berghammer }
2761d0d90b9STamas Berghammer 
277b9c1b51eSKate Stone uint32_t PlatformAndroid::GetDefaultMemoryCacheLineSize() {
278f2991488SPavel Labath   return g_android_default_cache_size;
279f2991488SPavel Labath }
280f2991488SPavel Labath 
281b9c1b51eSKate Stone uint32_t PlatformAndroid::GetSdkVersion() {
2821d0d90b9STamas Berghammer   if (!IsConnected())
2831d0d90b9STamas Berghammer     return 0;
2841d0d90b9STamas Berghammer 
2851d0d90b9STamas Berghammer   if (m_sdk_version != 0)
2861d0d90b9STamas Berghammer     return m_sdk_version;
2871d0d90b9STamas Berghammer 
2881d0d90b9STamas Berghammer   std::string version_string;
289d6a143fcSOleksiy Vyalov   AdbClient adb(m_device_id);
290b9c1b51eSKate Stone   Error error =
291b9c1b51eSKate Stone       adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string);
2923e8947beSTamas Berghammer   version_string = llvm::StringRef(version_string).trim().str();
2933e8947beSTamas Berghammer 
294b9c1b51eSKate Stone   if (error.Fail() || version_string.empty()) {
2951d0d90b9STamas Berghammer     Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM);
2961d0d90b9STamas Berghammer     if (log)
2973e8947beSTamas Berghammer       log->Printf("Get SDK version failed. (error: %s, output: %s)",
2983e8947beSTamas Berghammer                   error.AsCString(), version_string.c_str());
2991d0d90b9STamas Berghammer     return 0;
3001d0d90b9STamas Berghammer   }
3011d0d90b9STamas Berghammer 
3021d0d90b9STamas Berghammer   m_sdk_version = StringConvert::ToUInt32(version_string.c_str());
3031d0d90b9STamas Berghammer   return m_sdk_version;
3041d0d90b9STamas Berghammer }
305ec3f92a5STamas Berghammer 
306b9c1b51eSKate Stone Error PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
307b9c1b51eSKate Stone                                           const FileSpec &dst_file_spec) {
308ec3f92a5STamas Berghammer   // For oat file we can try to fetch additional debug info from the device
309dba6503aSTamas Berghammer   ConstString extension = module_sp->GetFileSpec().GetFileNameExtension();
310dba6503aSTamas Berghammer   if (extension != ConstString("oat") && extension != ConstString("odex"))
311b9c1b51eSKate Stone     return Error(
312b9c1b51eSKate Stone         "Symbol file downloading only supported for oat and odex files");
313ec3f92a5STamas Berghammer 
314ec3f92a5STamas Berghammer   // If we have no information about the platform file we can't execute oatdump
315ec3f92a5STamas Berghammer   if (!module_sp->GetPlatformFileSpec())
316ec3f92a5STamas Berghammer     return Error("No platform file specified");
317ec3f92a5STamas Berghammer 
318ec3f92a5STamas Berghammer   // Symbolizer isn't available before SDK version 23
319ec3f92a5STamas Berghammer   if (GetSdkVersion() < 23)
320ec3f92a5STamas Berghammer     return Error("Symbol file generation only supported on SDK 23+");
321ec3f92a5STamas Berghammer 
322ec3f92a5STamas Berghammer   // If we already have symtab then we don't have to try and generate one
323b9c1b51eSKate Stone   if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) !=
324b9c1b51eSKate Stone       nullptr)
325ec3f92a5STamas Berghammer     return Error("Symtab already available in the module");
326ec3f92a5STamas Berghammer 
327d6a143fcSOleksiy Vyalov   AdbClient adb(m_device_id);
3289d8dde8cSTamas Berghammer   std::string tmpdir;
329b9c1b51eSKate Stone   Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp",
330b9c1b51eSKate Stone                           5000 /* ms */, &tmpdir);
3319d8dde8cSTamas Berghammer   if (error.Fail() || tmpdir.empty())
332b9c1b51eSKate Stone     return Error("Failed to generate temporary directory on the device (%s)",
333b9c1b51eSKate Stone                  error.AsCString());
334539cd118STamas Berghammer   tmpdir = llvm::StringRef(tmpdir).trim().str();
335ec3f92a5STamas Berghammer 
336ec3f92a5STamas Berghammer   // Create file remover for the temporary directory created on the device
337b9c1b51eSKate Stone   std::unique_ptr<std::string, std::function<void(std::string *)>>
338b9c1b51eSKate Stone   tmpdir_remover(&tmpdir, [this, &adb](std::string *s) {
339ec3f92a5STamas Berghammer     StreamString command;
340ec3f92a5STamas Berghammer     command.Printf("rm -rf %s", s->c_str());
341d6a143fcSOleksiy Vyalov     Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr);
342ec3f92a5STamas Berghammer 
343ec3f92a5STamas Berghammer     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
344dd778ca6SOleksiy Vyalov     if (log && error.Fail())
345ec3f92a5STamas Berghammer       log->Printf("Failed to remove temp directory: %s", error.AsCString());
346b9c1b51eSKate Stone   });
347ec3f92a5STamas Berghammer 
348*771ef6d4SMalcolm Parsons   FileSpec symfile_platform_filespec(tmpdir, false);
349ec3f92a5STamas Berghammer   symfile_platform_filespec.AppendPathComponent("symbolized.oat");
350ec3f92a5STamas Berghammer 
351ec3f92a5STamas Berghammer   // Execute oatdump on the remote device to generate a file with symtab
3529d8dde8cSTamas Berghammer   StreamString command;
353ec3f92a5STamas Berghammer   command.Printf("oatdump --symbolize=%s --output=%s",
354ec3f92a5STamas Berghammer                  module_sp->GetPlatformFileSpec().GetCString(false),
355ec3f92a5STamas Berghammer                  symfile_platform_filespec.GetCString(false));
356d6a143fcSOleksiy Vyalov   error = adb.Shell(command.GetData(), 60000 /* ms */, nullptr);
3579d8dde8cSTamas Berghammer   if (error.Fail())
358ec3f92a5STamas Berghammer     return Error("Oatdump failed: %s", error.AsCString());
359ec3f92a5STamas Berghammer 
360ec3f92a5STamas Berghammer   // Download the symbolfile from the remote device
361ec3f92a5STamas Berghammer   return GetFile(symfile_platform_filespec, dst_file_spec);
362ec3f92a5STamas Berghammer }
3633c47151dSTamas Berghammer 
364b9c1b51eSKate Stone bool PlatformAndroid::GetRemoteOSVersion() {
3653c47151dSTamas Berghammer   m_major_os_version = GetSdkVersion();
3663c47151dSTamas Berghammer   m_minor_os_version = 0;
3673c47151dSTamas Berghammer   m_update_os_version = 0;
3683c47151dSTamas Berghammer   return m_major_os_version != 0;
3693c47151dSTamas Berghammer }
3703cb132a0STamas Berghammer 
371b9c1b51eSKate Stone const char *PlatformAndroid::GetLibdlFunctionDeclarations() const {
372fcdde63fSTamas Berghammer   return R"(
373fcdde63fSTamas Berghammer               extern "C" void* dlopen(const char*, int) asm("__dl_dlopen");
374fcdde63fSTamas Berghammer               extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym");
375fcdde63fSTamas Berghammer               extern "C" int   dlclose(void*) asm("__dl_dlclose");
376fcdde63fSTamas Berghammer               extern "C" char* dlerror(void) asm("__dl_dlerror");
3773cb132a0STamas Berghammer              )";
3783cb132a0STamas Berghammer }
379d6a143fcSOleksiy Vyalov 
380b9c1b51eSKate Stone AdbClient::SyncService *PlatformAndroid::GetSyncService(Error &error) {
381d6a143fcSOleksiy Vyalov   if (m_adb_sync_svc && m_adb_sync_svc->IsConnected())
382d6a143fcSOleksiy Vyalov     return m_adb_sync_svc.get();
383d6a143fcSOleksiy Vyalov 
384d6a143fcSOleksiy Vyalov   AdbClient adb(m_device_id);
385d6a143fcSOleksiy Vyalov   m_adb_sync_svc = adb.GetSyncService(error);
386d6a143fcSOleksiy Vyalov   return (error.Success()) ? m_adb_sync_svc.get() : nullptr;
387d6a143fcSOleksiy Vyalov }
388