1 //===-- PlatformAndroid.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 #include "lldb/Core/Log.h" 14 #include "lldb/Core/Module.h" 15 #include "lldb/Core/PluginManager.h" 16 #include "lldb/Core/Section.h" 17 #include "lldb/Host/HostInfo.h" 18 #include "lldb/Host/StringConvert.h" 19 #include "Utility/UriParser.h" 20 21 // Project includes 22 #include "AdbClient.h" 23 #include "PlatformAndroid.h" 24 #include "PlatformAndroidRemoteGDBServer.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 using namespace lldb_private::platform_android; 29 30 static uint32_t g_initialize_count = 0; 31 static const unsigned int g_android_default_cache_size = 2048; // Fits inside 4k adb packet. 32 33 void 34 PlatformAndroid::Initialize () 35 { 36 PlatformLinux::Initialize (); 37 38 if (g_initialize_count++ == 0) 39 { 40 #if defined(__ANDROID__) 41 PlatformSP default_platform_sp (new PlatformAndroid(true)); 42 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); 43 Platform::SetHostPlatform (default_platform_sp); 44 #endif 45 PluginManager::RegisterPlugin (PlatformAndroid::GetPluginNameStatic(false), 46 PlatformAndroid::GetPluginDescriptionStatic(false), 47 PlatformAndroid::CreateInstance); 48 } 49 } 50 51 void 52 PlatformAndroid::Terminate () 53 { 54 if (g_initialize_count > 0) 55 { 56 if (--g_initialize_count == 0) 57 { 58 PluginManager::UnregisterPlugin (PlatformAndroid::CreateInstance); 59 } 60 } 61 62 PlatformLinux::Terminate (); 63 } 64 65 PlatformSP 66 PlatformAndroid::CreateInstance (bool force, const ArchSpec *arch) 67 { 68 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 69 if (log) 70 { 71 const char *arch_name; 72 if (arch && arch->GetArchitectureName ()) 73 arch_name = arch->GetArchitectureName (); 74 else 75 arch_name = "<null>"; 76 77 const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>"; 78 79 log->Printf ("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); 80 } 81 82 bool create = force; 83 if (create == false && arch && arch->IsValid()) 84 { 85 const llvm::Triple &triple = arch->GetTriple(); 86 switch (triple.getVendor()) 87 { 88 case llvm::Triple::PC: 89 create = true; 90 break; 91 92 #if defined(__ANDROID__) 93 // Only accept "unknown" for the vendor if the host is android and 94 // it "unknown" wasn't specified (it was just returned because it 95 // was NOT specified_ 96 case llvm::Triple::VendorType::UnknownVendor: 97 create = !arch->TripleVendorWasSpecified(); 98 break; 99 #endif 100 default: 101 break; 102 } 103 104 if (create) 105 { 106 switch (triple.getOS()) 107 { 108 case llvm::Triple::Android: 109 break; 110 111 #if defined(__ANDROID__) 112 // Only accept "unknown" for the OS if the host is android and 113 // it "unknown" wasn't specified (it was just returned because it 114 // was NOT specified) 115 case llvm::Triple::OSType::UnknownOS: 116 create = !arch->TripleOSWasSpecified(); 117 break; 118 #endif 119 default: 120 create = false; 121 break; 122 } 123 } 124 } 125 126 if (create) 127 { 128 if (log) 129 log->Printf ("PlatformAndroid::%s() creating remote-android platform", __FUNCTION__); 130 return PlatformSP(new PlatformAndroid(false)); 131 } 132 133 if (log) 134 log->Printf ("PlatformAndroid::%s() aborting creation of remote-android platform", __FUNCTION__); 135 136 return PlatformSP(); 137 } 138 139 PlatformAndroid::PlatformAndroid (bool is_host) : 140 PlatformLinux(is_host), 141 m_sdk_version(0) 142 { 143 } 144 145 PlatformAndroid::~PlatformAndroid() 146 { 147 } 148 149 ConstString 150 PlatformAndroid::GetPluginNameStatic (bool is_host) 151 { 152 if (is_host) 153 { 154 static ConstString g_host_name(Platform::GetHostPlatformName ()); 155 return g_host_name; 156 } 157 else 158 { 159 static ConstString g_remote_name("remote-android"); 160 return g_remote_name; 161 } 162 } 163 164 const char * 165 PlatformAndroid::GetPluginDescriptionStatic (bool is_host) 166 { 167 if (is_host) 168 return "Local Android user platform plug-in."; 169 else 170 return "Remote Android user platform plug-in."; 171 } 172 173 ConstString 174 PlatformAndroid::GetPluginName() 175 { 176 return GetPluginNameStatic(IsHost()); 177 } 178 179 Error 180 PlatformAndroid::ConnectRemote(Args& args) 181 { 182 m_device_id.clear(); 183 184 if (IsHost()) 185 { 186 return Error ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString()); 187 } 188 189 if (!m_remote_platform_sp) 190 m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer()); 191 192 int port; 193 std::string scheme, host, path; 194 const char *url = args.GetArgumentAtIndex(0); 195 if (!url) 196 return Error("URL is null."); 197 if (!UriParser::Parse(url, scheme, host, port, path)) 198 return Error("Invalid URL: %s", url); 199 if (host != "localhost") 200 m_device_id = host; 201 202 auto error = PlatformLinux::ConnectRemote(args); 203 if (error.Success()) 204 { 205 AdbClient adb; 206 error = AdbClient::CreateByDeviceID(m_device_id, adb); 207 if (error.Fail()) 208 return error; 209 210 m_device_id = adb.GetDeviceID(); 211 } 212 return error; 213 } 214 215 Error 216 PlatformAndroid::GetFile (const FileSpec& source, 217 const FileSpec& destination) 218 { 219 if (IsHost() || !m_remote_platform_sp) 220 return PlatformLinux::GetFile(source, destination); 221 222 FileSpec source_spec (source.GetPath (false), false, FileSpec::ePathSyntaxPosix); 223 if (source_spec.IsRelative()) 224 source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false)); 225 226 AdbClient adb (m_device_id); 227 return adb.PullFile (source_spec, destination); 228 } 229 230 Error 231 PlatformAndroid::PutFile (const FileSpec& source, 232 const FileSpec& destination, 233 uint32_t uid, 234 uint32_t gid) 235 { 236 if (IsHost() || !m_remote_platform_sp) 237 return PlatformLinux::PutFile (source, destination, uid, gid); 238 239 FileSpec destination_spec (destination.GetPath (false), false, FileSpec::ePathSyntaxPosix); 240 if (destination_spec.IsRelative()) 241 destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false)); 242 243 AdbClient adb (m_device_id); 244 // TODO: Set correct uid and gid on remote file. 245 return adb.PushFile(source, destination_spec); 246 } 247 248 const char * 249 PlatformAndroid::GetCacheHostname () 250 { 251 return m_device_id.c_str (); 252 } 253 254 Error 255 PlatformAndroid::DownloadModuleSlice (const FileSpec &src_file_spec, 256 const uint64_t src_offset, 257 const uint64_t src_size, 258 const FileSpec &dst_file_spec) 259 { 260 if (src_offset != 0) 261 return Error ("Invalid offset - %" PRIu64, src_offset); 262 263 return GetFile (src_file_spec, dst_file_spec); 264 } 265 266 Error 267 PlatformAndroid::DisconnectRemote() 268 { 269 Error error = PlatformLinux::DisconnectRemote(); 270 if (error.Success()) 271 { 272 m_device_id.clear(); 273 m_sdk_version = 0; 274 } 275 return error; 276 } 277 278 uint32_t 279 PlatformAndroid::GetDefaultMemoryCacheLineSize() 280 { 281 return g_android_default_cache_size; 282 } 283 284 uint32_t 285 PlatformAndroid::GetSdkVersion() 286 { 287 if (!IsConnected()) 288 return 0; 289 290 if (m_sdk_version != 0) 291 return m_sdk_version; 292 293 std::string version_string; 294 AdbClient adb(m_device_id); 295 Error error = adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string); 296 version_string = llvm::StringRef(version_string).trim().str(); 297 298 if (error.Fail() || version_string.empty()) 299 { 300 Log* log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM); 301 if (log) 302 log->Printf("Get SDK version failed. (error: %s, output: %s)", 303 error.AsCString(), version_string.c_str()); 304 return 0; 305 } 306 307 m_sdk_version = StringConvert::ToUInt32(version_string.c_str()); 308 return m_sdk_version; 309 } 310 311 Error 312 PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp, 313 const FileSpec& dst_file_spec) 314 { 315 // For oat file we can try to fetch additional debug info from the device 316 if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat")) 317 return Error("Symbol file downloading only supported for oat files"); 318 319 // If we have no information about the platform file we can't execute oatdump 320 if (!module_sp->GetPlatformFileSpec()) 321 return Error("No platform file specified"); 322 323 // Symbolizer isn't available before SDK version 23 324 if (GetSdkVersion() < 23) 325 return Error("Symbol file generation only supported on SDK 23+"); 326 327 // If we already have symtab then we don't have to try and generate one 328 if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != nullptr) 329 return Error("Symtab already available in the module"); 330 331 AdbClient adb(m_device_id); 332 333 std::string tmpdir; 334 Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir); 335 if (error.Fail() || tmpdir.empty()) 336 return Error("Failed to generate temporary directory on the device (%s)", error.AsCString()); 337 tmpdir = llvm::StringRef(tmpdir).trim().str(); 338 339 // Create file remover for the temporary directory created on the device 340 std::unique_ptr<std::string, std::function<void(std::string*)>> tmpdir_remover( 341 &tmpdir, 342 [this, &adb](std::string* s) { 343 StreamString command; 344 command.Printf("rm -rf %s", s->c_str()); 345 Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr); 346 347 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 348 if (error.Fail()) 349 log->Printf("Failed to remove temp directory: %s", error.AsCString()); 350 } 351 ); 352 353 FileSpec symfile_platform_filespec(tmpdir.c_str(), false); 354 symfile_platform_filespec.AppendPathComponent("symbolized.oat"); 355 356 // Execute oatdump on the remote device to generate a file with symtab 357 StreamString command; 358 command.Printf("oatdump --symbolize=%s --output=%s", 359 module_sp->GetPlatformFileSpec().GetCString(false), 360 symfile_platform_filespec.GetCString(false)); 361 error = adb.Shell(command.GetData(), 60000 /* ms */, nullptr); 362 if (error.Fail()) 363 return Error("Oatdump failed: %s", error.AsCString()); 364 365 // Download the symbolfile from the remote device 366 return GetFile(symfile_platform_filespec, dst_file_spec); 367 } 368 369 bool 370 PlatformAndroid::GetRemoteOSVersion () 371 { 372 m_major_os_version = GetSdkVersion(); 373 m_minor_os_version = 0; 374 m_update_os_version = 0; 375 return m_major_os_version != 0; 376 } 377