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