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; 31f2991488SPavel Labath static const unsigned int g_android_default_cache_size = 2048; // Fits inside 4k adb packet. 3200e305d2STamas Berghammer 3300e305d2STamas Berghammer void 3400e305d2STamas Berghammer PlatformAndroid::Initialize () 3500e305d2STamas Berghammer { 363c4f89d7STamas Berghammer PlatformLinux::Initialize (); 373c4f89d7STamas Berghammer 3800e305d2STamas Berghammer if (g_initialize_count++ == 0) 3900e305d2STamas Berghammer { 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 451c6a1ea9STamas Berghammer PluginManager::RegisterPlugin (PlatformAndroid::GetPluginNameStatic(false), 461c6a1ea9STamas Berghammer PlatformAndroid::GetPluginDescriptionStatic(false), 4700e305d2STamas Berghammer PlatformAndroid::CreateInstance); 4800e305d2STamas Berghammer } 4900e305d2STamas Berghammer } 5000e305d2STamas Berghammer 5100e305d2STamas Berghammer void 5200e305d2STamas Berghammer PlatformAndroid::Terminate () 5300e305d2STamas Berghammer { 5400e305d2STamas Berghammer if (g_initialize_count > 0) 5500e305d2STamas Berghammer { 5600e305d2STamas Berghammer if (--g_initialize_count == 0) 5700e305d2STamas Berghammer { 5800e305d2STamas Berghammer PluginManager::UnregisterPlugin (PlatformAndroid::CreateInstance); 5900e305d2STamas Berghammer } 6000e305d2STamas Berghammer } 613c4f89d7STamas Berghammer 623c4f89d7STamas Berghammer PlatformLinux::Terminate (); 6300e305d2STamas Berghammer } 6400e305d2STamas Berghammer 6500e305d2STamas Berghammer PlatformSP 6600e305d2STamas Berghammer PlatformAndroid::CreateInstance (bool force, const ArchSpec *arch) 6700e305d2STamas Berghammer { 68db264a6dSTamas Berghammer Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 6900e305d2STamas Berghammer if (log) 7000e305d2STamas Berghammer { 7100e305d2STamas Berghammer const char *arch_name; 7200e305d2STamas Berghammer if (arch && arch->GetArchitectureName ()) 7300e305d2STamas Berghammer arch_name = arch->GetArchitectureName (); 7400e305d2STamas Berghammer else 7500e305d2STamas Berghammer arch_name = "<null>"; 7600e305d2STamas Berghammer 7700e305d2STamas Berghammer const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>"; 7800e305d2STamas Berghammer 7900e305d2STamas Berghammer log->Printf ("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); 8000e305d2STamas Berghammer } 8100e305d2STamas Berghammer 8200e305d2STamas Berghammer bool create = force; 8300e305d2STamas Berghammer if (create == false && arch && arch->IsValid()) 8400e305d2STamas Berghammer { 8500e305d2STamas Berghammer const llvm::Triple &triple = arch->GetTriple(); 8600e305d2STamas Berghammer switch (triple.getVendor()) 8700e305d2STamas Berghammer { 8800e305d2STamas Berghammer case llvm::Triple::PC: 8900e305d2STamas Berghammer create = true; 9000e305d2STamas Berghammer break; 9100e305d2STamas Berghammer 9200e305d2STamas Berghammer #if defined(__ANDROID__) 9300e305d2STamas Berghammer // Only accept "unknown" for the vendor if the host is android and 9400e305d2STamas Berghammer // it "unknown" wasn't specified (it was just returned because it 9500e305d2STamas Berghammer // was NOT specified_ 9600e305d2STamas Berghammer case llvm::Triple::VendorType::UnknownVendor: 9700e305d2STamas Berghammer create = !arch->TripleVendorWasSpecified(); 9800e305d2STamas Berghammer break; 9900e305d2STamas Berghammer #endif 10000e305d2STamas Berghammer default: 10100e305d2STamas Berghammer break; 10200e305d2STamas Berghammer } 10300e305d2STamas Berghammer 10400e305d2STamas Berghammer if (create) 10500e305d2STamas Berghammer { 10600e305d2STamas Berghammer switch (triple.getOS()) 10700e305d2STamas Berghammer { 1081c6a1ea9STamas Berghammer case llvm::Triple::Android: 10900e305d2STamas Berghammer break; 11000e305d2STamas Berghammer 11100e305d2STamas Berghammer #if defined(__ANDROID__) 11200e305d2STamas Berghammer // Only accept "unknown" for the OS if the host is android and 11300e305d2STamas Berghammer // it "unknown" wasn't specified (it was just returned because it 11400e305d2STamas Berghammer // was NOT specified) 11500e305d2STamas Berghammer case llvm::Triple::OSType::UnknownOS: 11600e305d2STamas Berghammer create = !arch->TripleOSWasSpecified(); 11700e305d2STamas Berghammer break; 11800e305d2STamas Berghammer #endif 11900e305d2STamas Berghammer default: 12000e305d2STamas Berghammer create = false; 12100e305d2STamas Berghammer break; 12200e305d2STamas Berghammer } 12300e305d2STamas Berghammer } 12400e305d2STamas Berghammer } 12500e305d2STamas Berghammer 12600e305d2STamas Berghammer if (create) 12700e305d2STamas Berghammer { 12800e305d2STamas Berghammer if (log) 12900e305d2STamas Berghammer log->Printf ("PlatformAndroid::%s() creating remote-android platform", __FUNCTION__); 1301c6a1ea9STamas Berghammer return PlatformSP(new PlatformAndroid(false)); 13100e305d2STamas Berghammer } 13200e305d2STamas Berghammer 13300e305d2STamas Berghammer if (log) 13400e305d2STamas Berghammer log->Printf ("PlatformAndroid::%s() aborting creation of remote-android platform", __FUNCTION__); 13500e305d2STamas Berghammer 13600e305d2STamas Berghammer return PlatformSP(); 13700e305d2STamas Berghammer } 13800e305d2STamas Berghammer 1391c6a1ea9STamas Berghammer PlatformAndroid::PlatformAndroid (bool is_host) : 1401d0d90b9STamas Berghammer PlatformLinux(is_host), 1411d0d90b9STamas Berghammer m_sdk_version(0) 14200e305d2STamas Berghammer { 14300e305d2STamas Berghammer } 14400e305d2STamas Berghammer 14500e305d2STamas Berghammer PlatformAndroid::~PlatformAndroid() 14600e305d2STamas Berghammer { 14700e305d2STamas Berghammer } 14800e305d2STamas Berghammer 149db264a6dSTamas Berghammer ConstString 1501c6a1ea9STamas Berghammer PlatformAndroid::GetPluginNameStatic (bool is_host) 1511c6a1ea9STamas Berghammer { 1521c6a1ea9STamas Berghammer if (is_host) 1531c6a1ea9STamas Berghammer { 1541c6a1ea9STamas Berghammer static ConstString g_host_name(Platform::GetHostPlatformName ()); 1551c6a1ea9STamas Berghammer return g_host_name; 1561c6a1ea9STamas Berghammer } 1571c6a1ea9STamas Berghammer else 15800e305d2STamas Berghammer { 15900e305d2STamas Berghammer static ConstString g_remote_name("remote-android"); 16000e305d2STamas Berghammer return g_remote_name; 16100e305d2STamas Berghammer } 1621c6a1ea9STamas Berghammer } 16300e305d2STamas Berghammer 16400e305d2STamas Berghammer const char * 1651c6a1ea9STamas Berghammer PlatformAndroid::GetPluginDescriptionStatic (bool is_host) 16600e305d2STamas Berghammer { 1671c6a1ea9STamas Berghammer if (is_host) 1681c6a1ea9STamas Berghammer return "Local Android user platform plug-in."; 1691c6a1ea9STamas Berghammer else 17000e305d2STamas Berghammer return "Remote Android user platform plug-in."; 17100e305d2STamas Berghammer } 17200e305d2STamas Berghammer 173db264a6dSTamas Berghammer ConstString 17400e305d2STamas Berghammer PlatformAndroid::GetPluginName() 17500e305d2STamas Berghammer { 1761c6a1ea9STamas Berghammer return GetPluginNameStatic(IsHost()); 17700e305d2STamas Berghammer } 17800e305d2STamas Berghammer 17900e305d2STamas Berghammer Error 18000e305d2STamas Berghammer PlatformAndroid::ConnectRemote(Args& args) 18100e305d2STamas Berghammer { 1826f001068SOleksiy Vyalov m_device_id.clear(); 1836f001068SOleksiy Vyalov 1841c6a1ea9STamas Berghammer if (IsHost()) 1851c6a1ea9STamas Berghammer { 1861c6a1ea9STamas Berghammer return Error ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString()); 1871c6a1ea9STamas Berghammer } 1881c6a1ea9STamas Berghammer 18900e305d2STamas Berghammer if (!m_remote_platform_sp) 19000e305d2STamas Berghammer m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer()); 1916f001068SOleksiy Vyalov 1923ea689b3SChaoren Lin int port; 1933ea689b3SChaoren Lin std::string scheme, host, path; 1943ea689b3SChaoren Lin const char *url = args.GetArgumentAtIndex(0); 1953ea689b3SChaoren Lin if (!url) 1963ea689b3SChaoren Lin return Error("URL is null."); 1973ea689b3SChaoren Lin if (!UriParser::Parse(url, scheme, host, port, path)) 1983ea689b3SChaoren Lin return Error("Invalid URL: %s", url); 199*a29d6475SOleksiy Vyalov if (host != "localhost") 2003ea689b3SChaoren Lin m_device_id = host; 2013ea689b3SChaoren Lin 2026f001068SOleksiy Vyalov auto error = PlatformLinux::ConnectRemote(args); 2036f001068SOleksiy Vyalov if (error.Success()) 2046f001068SOleksiy Vyalov { 2056f001068SOleksiy Vyalov AdbClient adb; 2063ea689b3SChaoren Lin error = AdbClient::CreateByDeviceID(m_device_id, adb); 2076f001068SOleksiy Vyalov if (error.Fail()) 2086f001068SOleksiy Vyalov return error; 2096f001068SOleksiy Vyalov 2106f001068SOleksiy Vyalov m_device_id = adb.GetDeviceID(); 2116f001068SOleksiy Vyalov } 2126f001068SOleksiy Vyalov return error; 2136f001068SOleksiy Vyalov } 2146f001068SOleksiy Vyalov 2150b5ebef7SOleksiy Vyalov Error 2160b5ebef7SOleksiy Vyalov PlatformAndroid::GetFile (const FileSpec& source, 2170b5ebef7SOleksiy Vyalov const FileSpec& destination) 2180b5ebef7SOleksiy Vyalov { 219291f59c5SOleksiy Vyalov if (IsHost() || !m_remote_platform_sp) 2200b5ebef7SOleksiy Vyalov return PlatformLinux::GetFile(source, destination); 221291f59c5SOleksiy Vyalov 22232a9da56SOleksiy Vyalov FileSpec source_spec (source.GetPath (false), false, FileSpec::ePathSyntaxPosix); 223372e9067SChaoren Lin if (source_spec.IsRelative()) 22432a9da56SOleksiy Vyalov source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false)); 225291f59c5SOleksiy Vyalov 226291f59c5SOleksiy Vyalov AdbClient adb (m_device_id); 227291f59c5SOleksiy Vyalov return adb.PullFile (source_spec, destination); 2280b5ebef7SOleksiy Vyalov } 2290b5ebef7SOleksiy Vyalov 2300b5ebef7SOleksiy Vyalov Error 2310b5ebef7SOleksiy Vyalov PlatformAndroid::PutFile (const FileSpec& source, 2320b5ebef7SOleksiy Vyalov const FileSpec& destination, 23362efb1f6SRobert Flack uint32_t uid, 23462efb1f6SRobert Flack uint32_t gid) 23562efb1f6SRobert Flack { 23617701b59SOleksiy Vyalov if (IsHost() || !m_remote_platform_sp) 23717701b59SOleksiy Vyalov return PlatformLinux::PutFile (source, destination, uid, gid); 23817701b59SOleksiy Vyalov 23917701b59SOleksiy Vyalov FileSpec destination_spec (destination.GetPath (false), false, FileSpec::ePathSyntaxPosix); 240372e9067SChaoren Lin if (destination_spec.IsRelative()) 24117701b59SOleksiy Vyalov destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false)); 24217701b59SOleksiy Vyalov 24362efb1f6SRobert Flack AdbClient adb (m_device_id); 24462efb1f6SRobert Flack // TODO: Set correct uid and gid on remote file. 24517701b59SOleksiy Vyalov return adb.PushFile(source, destination_spec); 24662efb1f6SRobert Flack } 24762efb1f6SRobert Flack 2486f001068SOleksiy Vyalov const char * 2496f001068SOleksiy Vyalov PlatformAndroid::GetCacheHostname () 2506f001068SOleksiy Vyalov { 2516f001068SOleksiy Vyalov return m_device_id.c_str (); 25200e305d2STamas Berghammer } 25309e9079dSOleksiy Vyalov 25409e9079dSOleksiy Vyalov Error 25509e9079dSOleksiy Vyalov PlatformAndroid::DownloadModuleSlice (const FileSpec &src_file_spec, 25609e9079dSOleksiy Vyalov const uint64_t src_offset, 25709e9079dSOleksiy Vyalov const uint64_t src_size, 25809e9079dSOleksiy Vyalov const FileSpec &dst_file_spec) 25909e9079dSOleksiy Vyalov { 26009e9079dSOleksiy Vyalov if (src_offset != 0) 26109e9079dSOleksiy Vyalov return Error ("Invalid offset - %" PRIu64, src_offset); 26209e9079dSOleksiy Vyalov 2630b5ebef7SOleksiy Vyalov return GetFile (src_file_spec, dst_file_spec); 26409e9079dSOleksiy Vyalov } 2651d0d90b9STamas Berghammer 2661d0d90b9STamas Berghammer Error 2671d0d90b9STamas Berghammer PlatformAndroid::DisconnectRemote() 2681d0d90b9STamas Berghammer { 2691d0d90b9STamas Berghammer Error error = PlatformLinux::DisconnectRemote(); 2701d0d90b9STamas Berghammer if (error.Success()) 2711d0d90b9STamas Berghammer { 2721d0d90b9STamas Berghammer m_device_id.clear(); 2731d0d90b9STamas Berghammer m_sdk_version = 0; 2741d0d90b9STamas Berghammer } 2751d0d90b9STamas Berghammer return error; 2761d0d90b9STamas Berghammer } 2771d0d90b9STamas Berghammer 2781d0d90b9STamas Berghammer uint32_t 279f2991488SPavel Labath PlatformAndroid::GetDefaultMemoryCacheLineSize() 280f2991488SPavel Labath { 281f2991488SPavel Labath return g_android_default_cache_size; 282f2991488SPavel Labath } 283f2991488SPavel Labath 284f2991488SPavel Labath uint32_t 2851d0d90b9STamas Berghammer PlatformAndroid::GetSdkVersion() 2861d0d90b9STamas Berghammer { 2871d0d90b9STamas Berghammer if (!IsConnected()) 2881d0d90b9STamas Berghammer return 0; 2891d0d90b9STamas Berghammer 2901d0d90b9STamas Berghammer if (m_sdk_version != 0) 2911d0d90b9STamas Berghammer return m_sdk_version; 2921d0d90b9STamas Berghammer 2931d0d90b9STamas Berghammer std::string version_string; 2943e8947beSTamas Berghammer AdbClient adb(m_device_id); 2953e8947beSTamas Berghammer Error error = adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string); 2963e8947beSTamas Berghammer version_string = llvm::StringRef(version_string).trim().str(); 2973e8947beSTamas Berghammer 2983e8947beSTamas Berghammer if (error.Fail() || version_string.empty()) 2991d0d90b9STamas Berghammer { 3001d0d90b9STamas Berghammer Log* log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM); 3011d0d90b9STamas Berghammer if (log) 3023e8947beSTamas Berghammer log->Printf("Get SDK version failed. (error: %s, output: %s)", 3033e8947beSTamas Berghammer error.AsCString(), version_string.c_str()); 3041d0d90b9STamas Berghammer return 0; 3051d0d90b9STamas Berghammer } 3061d0d90b9STamas Berghammer 3071d0d90b9STamas Berghammer m_sdk_version = StringConvert::ToUInt32(version_string.c_str()); 3081d0d90b9STamas Berghammer return m_sdk_version; 3091d0d90b9STamas Berghammer } 310ec3f92a5STamas Berghammer 311ec3f92a5STamas Berghammer Error 312ec3f92a5STamas Berghammer PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp, 313ec3f92a5STamas Berghammer const FileSpec& dst_file_spec) 314ec3f92a5STamas Berghammer { 315ec3f92a5STamas Berghammer // For oat file we can try to fetch additional debug info from the device 316ec3f92a5STamas Berghammer if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat")) 317ec3f92a5STamas Berghammer return Error("Symbol file downloading only supported for oat files"); 318ec3f92a5STamas Berghammer 319ec3f92a5STamas Berghammer // If we have no information about the platform file we can't execute oatdump 320ec3f92a5STamas Berghammer if (!module_sp->GetPlatformFileSpec()) 321ec3f92a5STamas Berghammer return Error("No platform file specified"); 322ec3f92a5STamas Berghammer 323ec3f92a5STamas Berghammer // Symbolizer isn't available before SDK version 23 324ec3f92a5STamas Berghammer if (GetSdkVersion() < 23) 325ec3f92a5STamas Berghammer return Error("Symbol file generation only supported on SDK 23+"); 326ec3f92a5STamas Berghammer 327ec3f92a5STamas Berghammer // If we already have symtab then we don't have to try and generate one 328ec3f92a5STamas Berghammer if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != nullptr) 329ec3f92a5STamas Berghammer return Error("Symtab already available in the module"); 330ec3f92a5STamas Berghammer 3319d8dde8cSTamas Berghammer AdbClient adb(m_device_id); 332ec3f92a5STamas Berghammer 3339d8dde8cSTamas Berghammer std::string tmpdir; 3349d8dde8cSTamas Berghammer Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir); 3359d8dde8cSTamas Berghammer if (error.Fail() || tmpdir.empty()) 336ec3f92a5STamas Berghammer return Error("Failed to generate temporary directory on the device (%s)", error.AsCString()); 337539cd118STamas Berghammer tmpdir = llvm::StringRef(tmpdir).trim().str(); 338ec3f92a5STamas Berghammer 339ec3f92a5STamas Berghammer // Create file remover for the temporary directory created on the device 340ec3f92a5STamas Berghammer std::unique_ptr<std::string, std::function<void(std::string*)>> tmpdir_remover( 341ec3f92a5STamas Berghammer &tmpdir, 3429d8dde8cSTamas Berghammer [this, &adb](std::string* s) { 343ec3f92a5STamas Berghammer StreamString command; 344ec3f92a5STamas Berghammer command.Printf("rm -rf %s", s->c_str()); 3459d8dde8cSTamas Berghammer Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr); 346ec3f92a5STamas Berghammer 347ec3f92a5STamas Berghammer Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 348ec3f92a5STamas Berghammer if (error.Fail()) 349ec3f92a5STamas Berghammer log->Printf("Failed to remove temp directory: %s", error.AsCString()); 350ec3f92a5STamas Berghammer } 351ec3f92a5STamas Berghammer ); 352ec3f92a5STamas Berghammer 353ec3f92a5STamas Berghammer FileSpec symfile_platform_filespec(tmpdir.c_str(), false); 354ec3f92a5STamas Berghammer symfile_platform_filespec.AppendPathComponent("symbolized.oat"); 355ec3f92a5STamas Berghammer 356ec3f92a5STamas Berghammer // Execute oatdump on the remote device to generate a file with symtab 3579d8dde8cSTamas Berghammer StreamString command; 358ec3f92a5STamas Berghammer command.Printf("oatdump --symbolize=%s --output=%s", 359ec3f92a5STamas Berghammer module_sp->GetPlatformFileSpec().GetCString(false), 360ec3f92a5STamas Berghammer symfile_platform_filespec.GetCString(false)); 3619d8dde8cSTamas Berghammer error = adb.Shell(command.GetData(), 60000 /* ms */, nullptr); 3629d8dde8cSTamas Berghammer if (error.Fail()) 363ec3f92a5STamas Berghammer return Error("Oatdump failed: %s", error.AsCString()); 364ec3f92a5STamas Berghammer 365ec3f92a5STamas Berghammer // Download the symbolfile from the remote device 366ec3f92a5STamas Berghammer return GetFile(symfile_platform_filespec, dst_file_spec); 367ec3f92a5STamas Berghammer } 3683c47151dSTamas Berghammer 3693c47151dSTamas Berghammer bool 3703c47151dSTamas Berghammer PlatformAndroid::GetRemoteOSVersion () 3713c47151dSTamas Berghammer { 3723c47151dSTamas Berghammer m_major_os_version = GetSdkVersion(); 3733c47151dSTamas Berghammer m_minor_os_version = 0; 3743c47151dSTamas Berghammer m_update_os_version = 0; 3753c47151dSTamas Berghammer return m_major_os_version != 0; 3763c47151dSTamas Berghammer } 377