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