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 1300e305d2STamas Berghammer #include "lldb/Core/Log.h" 14ec3f92a5STamas Berghammer #include "lldb/Core/Module.h" 1500e305d2STamas Berghammer #include "lldb/Core/PluginManager.h" 16ec3f92a5STamas Berghammer #include "lldb/Core/Section.h" 171c6a1ea9STamas Berghammer #include "lldb/Host/HostInfo.h" 181d0d90b9STamas Berghammer #include "lldb/Host/StringConvert.h" 193ea689b3SChaoren Lin #include "Utility/UriParser.h" 2000e305d2STamas Berghammer 2100e305d2STamas Berghammer // Project includes 226f001068SOleksiy Vyalov #include "AdbClient.h" 2300e305d2STamas Berghammer #include "PlatformAndroid.h" 2400e305d2STamas Berghammer #include "PlatformAndroidRemoteGDBServer.h" 2500e305d2STamas Berghammer 2600e305d2STamas Berghammer using namespace lldb; 2700e305d2STamas Berghammer using namespace lldb_private; 28db264a6dSTamas Berghammer using namespace lldb_private::platform_android; 2900e305d2STamas Berghammer 3000e305d2STamas Berghammer static uint32_t g_initialize_count = 0; 3100e305d2STamas Berghammer 3200e305d2STamas Berghammer void 3300e305d2STamas Berghammer PlatformAndroid::Initialize () 3400e305d2STamas Berghammer { 353c4f89d7STamas Berghammer PlatformLinux::Initialize (); 363c4f89d7STamas Berghammer 3700e305d2STamas Berghammer if (g_initialize_count++ == 0) 3800e305d2STamas Berghammer { 391c6a1ea9STamas Berghammer #if defined(__ANDROID__) 401c6a1ea9STamas Berghammer PlatformSP default_platform_sp (new PlatformAndroid(true)); 411c6a1ea9STamas Berghammer default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); 421c6a1ea9STamas Berghammer Platform::SetHostPlatform (default_platform_sp); 431c6a1ea9STamas Berghammer #endif 441c6a1ea9STamas Berghammer PluginManager::RegisterPlugin (PlatformAndroid::GetPluginNameStatic(false), 451c6a1ea9STamas Berghammer PlatformAndroid::GetPluginDescriptionStatic(false), 4600e305d2STamas Berghammer PlatformAndroid::CreateInstance); 4700e305d2STamas Berghammer } 4800e305d2STamas Berghammer } 4900e305d2STamas Berghammer 5000e305d2STamas Berghammer void 5100e305d2STamas Berghammer PlatformAndroid::Terminate () 5200e305d2STamas Berghammer { 5300e305d2STamas Berghammer if (g_initialize_count > 0) 5400e305d2STamas Berghammer { 5500e305d2STamas Berghammer if (--g_initialize_count == 0) 5600e305d2STamas Berghammer { 5700e305d2STamas Berghammer PluginManager::UnregisterPlugin (PlatformAndroid::CreateInstance); 5800e305d2STamas Berghammer } 5900e305d2STamas Berghammer } 603c4f89d7STamas Berghammer 613c4f89d7STamas Berghammer PlatformLinux::Terminate (); 6200e305d2STamas Berghammer } 6300e305d2STamas Berghammer 6400e305d2STamas Berghammer PlatformSP 6500e305d2STamas Berghammer PlatformAndroid::CreateInstance (bool force, const ArchSpec *arch) 6600e305d2STamas Berghammer { 67db264a6dSTamas Berghammer Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 6800e305d2STamas Berghammer if (log) 6900e305d2STamas Berghammer { 7000e305d2STamas Berghammer const char *arch_name; 7100e305d2STamas Berghammer if (arch && arch->GetArchitectureName ()) 7200e305d2STamas Berghammer arch_name = arch->GetArchitectureName (); 7300e305d2STamas Berghammer else 7400e305d2STamas Berghammer arch_name = "<null>"; 7500e305d2STamas Berghammer 7600e305d2STamas Berghammer const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>"; 7700e305d2STamas Berghammer 7800e305d2STamas Berghammer log->Printf ("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); 7900e305d2STamas Berghammer } 8000e305d2STamas Berghammer 8100e305d2STamas Berghammer bool create = force; 8200e305d2STamas Berghammer if (create == false && arch && arch->IsValid()) 8300e305d2STamas Berghammer { 8400e305d2STamas Berghammer const llvm::Triple &triple = arch->GetTriple(); 8500e305d2STamas Berghammer switch (triple.getVendor()) 8600e305d2STamas Berghammer { 8700e305d2STamas Berghammer case llvm::Triple::PC: 8800e305d2STamas Berghammer create = true; 8900e305d2STamas Berghammer break; 9000e305d2STamas Berghammer 9100e305d2STamas Berghammer #if defined(__ANDROID__) 9200e305d2STamas Berghammer // Only accept "unknown" for the vendor if the host is android and 9300e305d2STamas Berghammer // it "unknown" wasn't specified (it was just returned because it 9400e305d2STamas Berghammer // was NOT specified_ 9500e305d2STamas Berghammer case llvm::Triple::VendorType::UnknownVendor: 9600e305d2STamas Berghammer create = !arch->TripleVendorWasSpecified(); 9700e305d2STamas Berghammer break; 9800e305d2STamas Berghammer #endif 9900e305d2STamas Berghammer default: 10000e305d2STamas Berghammer break; 10100e305d2STamas Berghammer } 10200e305d2STamas Berghammer 10300e305d2STamas Berghammer if (create) 10400e305d2STamas Berghammer { 10500e305d2STamas Berghammer switch (triple.getOS()) 10600e305d2STamas Berghammer { 1071c6a1ea9STamas Berghammer case llvm::Triple::Android: 10800e305d2STamas Berghammer break; 10900e305d2STamas Berghammer 11000e305d2STamas Berghammer #if defined(__ANDROID__) 11100e305d2STamas Berghammer // Only accept "unknown" for the OS if the host is android and 11200e305d2STamas Berghammer // it "unknown" wasn't specified (it was just returned because it 11300e305d2STamas Berghammer // was NOT specified) 11400e305d2STamas Berghammer case llvm::Triple::OSType::UnknownOS: 11500e305d2STamas Berghammer create = !arch->TripleOSWasSpecified(); 11600e305d2STamas Berghammer break; 11700e305d2STamas Berghammer #endif 11800e305d2STamas Berghammer default: 11900e305d2STamas Berghammer create = false; 12000e305d2STamas Berghammer break; 12100e305d2STamas Berghammer } 12200e305d2STamas Berghammer } 12300e305d2STamas Berghammer } 12400e305d2STamas Berghammer 12500e305d2STamas Berghammer if (create) 12600e305d2STamas Berghammer { 12700e305d2STamas Berghammer if (log) 12800e305d2STamas Berghammer log->Printf ("PlatformAndroid::%s() creating remote-android platform", __FUNCTION__); 1291c6a1ea9STamas Berghammer return PlatformSP(new PlatformAndroid(false)); 13000e305d2STamas Berghammer } 13100e305d2STamas Berghammer 13200e305d2STamas Berghammer if (log) 13300e305d2STamas Berghammer log->Printf ("PlatformAndroid::%s() aborting creation of remote-android platform", __FUNCTION__); 13400e305d2STamas Berghammer 13500e305d2STamas Berghammer return PlatformSP(); 13600e305d2STamas Berghammer } 13700e305d2STamas Berghammer 1381c6a1ea9STamas Berghammer PlatformAndroid::PlatformAndroid (bool is_host) : 1391d0d90b9STamas Berghammer PlatformLinux(is_host), 1401d0d90b9STamas Berghammer m_sdk_version(0) 14100e305d2STamas Berghammer { 14200e305d2STamas Berghammer } 14300e305d2STamas Berghammer 14400e305d2STamas Berghammer PlatformAndroid::~PlatformAndroid() 14500e305d2STamas Berghammer { 14600e305d2STamas Berghammer } 14700e305d2STamas Berghammer 148db264a6dSTamas Berghammer ConstString 1491c6a1ea9STamas Berghammer PlatformAndroid::GetPluginNameStatic (bool is_host) 1501c6a1ea9STamas Berghammer { 1511c6a1ea9STamas Berghammer if (is_host) 1521c6a1ea9STamas Berghammer { 1531c6a1ea9STamas Berghammer static ConstString g_host_name(Platform::GetHostPlatformName ()); 1541c6a1ea9STamas Berghammer return g_host_name; 1551c6a1ea9STamas Berghammer } 1561c6a1ea9STamas Berghammer else 15700e305d2STamas Berghammer { 15800e305d2STamas Berghammer static ConstString g_remote_name("remote-android"); 15900e305d2STamas Berghammer return g_remote_name; 16000e305d2STamas Berghammer } 1611c6a1ea9STamas Berghammer } 16200e305d2STamas Berghammer 16300e305d2STamas Berghammer const char * 1641c6a1ea9STamas Berghammer PlatformAndroid::GetPluginDescriptionStatic (bool is_host) 16500e305d2STamas Berghammer { 1661c6a1ea9STamas Berghammer if (is_host) 1671c6a1ea9STamas Berghammer return "Local Android user platform plug-in."; 1681c6a1ea9STamas Berghammer else 16900e305d2STamas Berghammer return "Remote Android user platform plug-in."; 17000e305d2STamas Berghammer } 17100e305d2STamas Berghammer 172db264a6dSTamas Berghammer ConstString 17300e305d2STamas Berghammer PlatformAndroid::GetPluginName() 17400e305d2STamas Berghammer { 1751c6a1ea9STamas Berghammer return GetPluginNameStatic(IsHost()); 17600e305d2STamas Berghammer } 17700e305d2STamas Berghammer 17800e305d2STamas Berghammer Error 17900e305d2STamas Berghammer PlatformAndroid::ConnectRemote(Args& args) 18000e305d2STamas Berghammer { 1816f001068SOleksiy Vyalov m_device_id.clear(); 1826f001068SOleksiy Vyalov 1831c6a1ea9STamas Berghammer if (IsHost()) 1841c6a1ea9STamas Berghammer { 1851c6a1ea9STamas Berghammer return Error ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString()); 1861c6a1ea9STamas Berghammer } 1871c6a1ea9STamas Berghammer 18800e305d2STamas Berghammer if (!m_remote_platform_sp) 18900e305d2STamas Berghammer m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer()); 1906f001068SOleksiy Vyalov 1913ea689b3SChaoren Lin int port; 1923ea689b3SChaoren Lin std::string scheme, host, path; 1933ea689b3SChaoren Lin const char *url = args.GetArgumentAtIndex(0); 1943ea689b3SChaoren Lin if (!url) 1953ea689b3SChaoren Lin return Error("URL is null."); 1963ea689b3SChaoren Lin if (!UriParser::Parse(url, scheme, host, port, path)) 1973ea689b3SChaoren Lin return Error("Invalid URL: %s", url); 1983ea689b3SChaoren Lin if (scheme == "adb") 1993ea689b3SChaoren Lin m_device_id = host; 2003ea689b3SChaoren Lin 2016f001068SOleksiy Vyalov auto error = PlatformLinux::ConnectRemote(args); 2026f001068SOleksiy Vyalov if (error.Success()) 2036f001068SOleksiy Vyalov { 2046f001068SOleksiy Vyalov AdbClient adb; 2053ea689b3SChaoren Lin error = AdbClient::CreateByDeviceID(m_device_id, adb); 2066f001068SOleksiy Vyalov if (error.Fail()) 2076f001068SOleksiy Vyalov return error; 2086f001068SOleksiy Vyalov 2096f001068SOleksiy Vyalov m_device_id = adb.GetDeviceID(); 2106f001068SOleksiy Vyalov } 2116f001068SOleksiy Vyalov return error; 2126f001068SOleksiy Vyalov } 2136f001068SOleksiy Vyalov 2140b5ebef7SOleksiy Vyalov Error 2150b5ebef7SOleksiy Vyalov PlatformAndroid::GetFile (const FileSpec& source, 2160b5ebef7SOleksiy Vyalov const FileSpec& destination) 2170b5ebef7SOleksiy Vyalov { 218291f59c5SOleksiy Vyalov if (IsHost() || !m_remote_platform_sp) 2190b5ebef7SOleksiy Vyalov return PlatformLinux::GetFile(source, destination); 220291f59c5SOleksiy Vyalov 22132a9da56SOleksiy Vyalov FileSpec source_spec (source.GetPath (false), false, FileSpec::ePathSyntaxPosix); 222372e9067SChaoren Lin if (source_spec.IsRelative()) 22332a9da56SOleksiy Vyalov source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false)); 224291f59c5SOleksiy Vyalov 225291f59c5SOleksiy Vyalov AdbClient adb (m_device_id); 226291f59c5SOleksiy Vyalov return adb.PullFile (source_spec, destination); 2270b5ebef7SOleksiy Vyalov } 2280b5ebef7SOleksiy Vyalov 2290b5ebef7SOleksiy Vyalov Error 2300b5ebef7SOleksiy Vyalov PlatformAndroid::PutFile (const FileSpec& source, 2310b5ebef7SOleksiy Vyalov const FileSpec& destination, 23262efb1f6SRobert Flack uint32_t uid, 23362efb1f6SRobert Flack uint32_t gid) 23462efb1f6SRobert Flack { 23517701b59SOleksiy Vyalov if (IsHost() || !m_remote_platform_sp) 23617701b59SOleksiy Vyalov return PlatformLinux::PutFile (source, destination, uid, gid); 23717701b59SOleksiy Vyalov 23817701b59SOleksiy Vyalov FileSpec destination_spec (destination.GetPath (false), false, FileSpec::ePathSyntaxPosix); 239372e9067SChaoren Lin if (destination_spec.IsRelative()) 24017701b59SOleksiy Vyalov destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false)); 24117701b59SOleksiy Vyalov 24262efb1f6SRobert Flack AdbClient adb (m_device_id); 24362efb1f6SRobert Flack // TODO: Set correct uid and gid on remote file. 24417701b59SOleksiy Vyalov return adb.PushFile(source, destination_spec); 24562efb1f6SRobert Flack } 24662efb1f6SRobert Flack 2476f001068SOleksiy Vyalov const char * 2486f001068SOleksiy Vyalov PlatformAndroid::GetCacheHostname () 2496f001068SOleksiy Vyalov { 2506f001068SOleksiy Vyalov return m_device_id.c_str (); 25100e305d2STamas Berghammer } 25209e9079dSOleksiy Vyalov 25309e9079dSOleksiy Vyalov Error 25409e9079dSOleksiy Vyalov PlatformAndroid::DownloadModuleSlice (const FileSpec &src_file_spec, 25509e9079dSOleksiy Vyalov const uint64_t src_offset, 25609e9079dSOleksiy Vyalov const uint64_t src_size, 25709e9079dSOleksiy Vyalov const FileSpec &dst_file_spec) 25809e9079dSOleksiy Vyalov { 25909e9079dSOleksiy Vyalov if (src_offset != 0) 26009e9079dSOleksiy Vyalov return Error ("Invalid offset - %" PRIu64, src_offset); 26109e9079dSOleksiy Vyalov 2620b5ebef7SOleksiy Vyalov return GetFile (src_file_spec, dst_file_spec); 26309e9079dSOleksiy Vyalov } 2641d0d90b9STamas Berghammer 2651d0d90b9STamas Berghammer Error 2661d0d90b9STamas Berghammer PlatformAndroid::DisconnectRemote() 2671d0d90b9STamas Berghammer { 2681d0d90b9STamas Berghammer Error error = PlatformLinux::DisconnectRemote(); 2691d0d90b9STamas Berghammer if (error.Success()) 2701d0d90b9STamas Berghammer { 2711d0d90b9STamas Berghammer m_device_id.clear(); 2721d0d90b9STamas Berghammer m_sdk_version = 0; 2731d0d90b9STamas Berghammer } 2741d0d90b9STamas Berghammer return error; 2751d0d90b9STamas Berghammer } 2761d0d90b9STamas Berghammer 2771d0d90b9STamas Berghammer uint32_t 2781d0d90b9STamas Berghammer PlatformAndroid::GetSdkVersion() 2791d0d90b9STamas Berghammer { 2801d0d90b9STamas Berghammer if (!IsConnected()) 2811d0d90b9STamas Berghammer return 0; 2821d0d90b9STamas Berghammer 2831d0d90b9STamas Berghammer if (m_sdk_version != 0) 2841d0d90b9STamas Berghammer return m_sdk_version; 2851d0d90b9STamas Berghammer 2861d0d90b9STamas Berghammer std::string version_string; 287*3e8947beSTamas Berghammer AdbClient adb(m_device_id); 288*3e8947beSTamas Berghammer Error error = adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string); 289*3e8947beSTamas Berghammer version_string = llvm::StringRef(version_string).trim().str(); 290*3e8947beSTamas Berghammer 291*3e8947beSTamas Berghammer if (error.Fail() || version_string.empty()) 2921d0d90b9STamas Berghammer { 2931d0d90b9STamas Berghammer Log* log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM); 2941d0d90b9STamas Berghammer if (log) 295*3e8947beSTamas Berghammer log->Printf("Get SDK version failed. (error: %s, output: %s)", 296*3e8947beSTamas Berghammer error.AsCString(), version_string.c_str()); 2971d0d90b9STamas Berghammer return 0; 2981d0d90b9STamas Berghammer } 2991d0d90b9STamas Berghammer 3001d0d90b9STamas Berghammer m_sdk_version = StringConvert::ToUInt32(version_string.c_str()); 3011d0d90b9STamas Berghammer return m_sdk_version; 3021d0d90b9STamas Berghammer } 303ec3f92a5STamas Berghammer 304ec3f92a5STamas Berghammer Error 305ec3f92a5STamas Berghammer PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp, 306ec3f92a5STamas Berghammer const FileSpec& dst_file_spec) 307ec3f92a5STamas Berghammer { 308ec3f92a5STamas Berghammer // For oat file we can try to fetch additional debug info from the device 309ec3f92a5STamas Berghammer if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat")) 310ec3f92a5STamas Berghammer return Error("Symbol file downloading only supported for oat files"); 311ec3f92a5STamas Berghammer 312ec3f92a5STamas Berghammer // If we have no information about the platform file we can't execute oatdump 313ec3f92a5STamas Berghammer if (!module_sp->GetPlatformFileSpec()) 314ec3f92a5STamas Berghammer return Error("No platform file specified"); 315ec3f92a5STamas Berghammer 316ec3f92a5STamas Berghammer // Symbolizer isn't available before SDK version 23 317ec3f92a5STamas Berghammer if (GetSdkVersion() < 23) 318ec3f92a5STamas Berghammer return Error("Symbol file generation only supported on SDK 23+"); 319ec3f92a5STamas Berghammer 320ec3f92a5STamas Berghammer // If we already have symtab then we don't have to try and generate one 321ec3f92a5STamas Berghammer if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != nullptr) 322ec3f92a5STamas Berghammer return Error("Symtab already available in the module"); 323ec3f92a5STamas Berghammer 3249d8dde8cSTamas Berghammer AdbClient adb(m_device_id); 325ec3f92a5STamas Berghammer 3269d8dde8cSTamas Berghammer std::string tmpdir; 3279d8dde8cSTamas Berghammer Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir); 3289d8dde8cSTamas Berghammer if (error.Fail() || tmpdir.empty()) 329ec3f92a5STamas Berghammer return Error("Failed to generate temporary directory on the device (%s)", error.AsCString()); 330539cd118STamas Berghammer tmpdir = llvm::StringRef(tmpdir).trim().str(); 331ec3f92a5STamas Berghammer 332ec3f92a5STamas Berghammer // Create file remover for the temporary directory created on the device 333ec3f92a5STamas Berghammer std::unique_ptr<std::string, std::function<void(std::string*)>> tmpdir_remover( 334ec3f92a5STamas Berghammer &tmpdir, 3359d8dde8cSTamas Berghammer [this, &adb](std::string* s) { 336ec3f92a5STamas Berghammer StreamString command; 337ec3f92a5STamas Berghammer command.Printf("rm -rf %s", s->c_str()); 3389d8dde8cSTamas Berghammer Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr); 339ec3f92a5STamas Berghammer 340ec3f92a5STamas Berghammer Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 341ec3f92a5STamas Berghammer if (error.Fail()) 342ec3f92a5STamas Berghammer log->Printf("Failed to remove temp directory: %s", error.AsCString()); 343ec3f92a5STamas Berghammer } 344ec3f92a5STamas Berghammer ); 345ec3f92a5STamas Berghammer 346ec3f92a5STamas Berghammer FileSpec symfile_platform_filespec(tmpdir.c_str(), false); 347ec3f92a5STamas Berghammer symfile_platform_filespec.AppendPathComponent("symbolized.oat"); 348ec3f92a5STamas Berghammer 349ec3f92a5STamas Berghammer // Execute oatdump on the remote device to generate a file with symtab 3509d8dde8cSTamas Berghammer StreamString command; 351ec3f92a5STamas Berghammer command.Printf("oatdump --symbolize=%s --output=%s", 352ec3f92a5STamas Berghammer module_sp->GetPlatformFileSpec().GetCString(false), 353ec3f92a5STamas Berghammer symfile_platform_filespec.GetCString(false)); 3549d8dde8cSTamas Berghammer error = adb.Shell(command.GetData(), 60000 /* ms */, nullptr); 3559d8dde8cSTamas Berghammer if (error.Fail()) 356ec3f92a5STamas Berghammer return Error("Oatdump failed: %s", error.AsCString()); 357ec3f92a5STamas Berghammer 358ec3f92a5STamas Berghammer // Download the symbolfile from the remote device 359ec3f92a5STamas Berghammer return GetFile(symfile_platform_filespec, dst_file_spec); 360ec3f92a5STamas Berghammer } 3613c47151dSTamas Berghammer 3623c47151dSTamas Berghammer bool 3633c47151dSTamas Berghammer PlatformAndroid::GetRemoteOSVersion () 3643c47151dSTamas Berghammer { 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 } 370