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/PluginManager.h"
15 #include "lldb/Host/HostInfo.h"
16 #include "Utility/UriParser.h"
17 
18 // Project includes
19 #include "AdbClient.h"
20 #include "PlatformAndroid.h"
21 #include "PlatformAndroidRemoteGDBServer.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 using namespace lldb_private::platform_android;
26 
27 static uint32_t g_initialize_count = 0;
28 
29 void
30 PlatformAndroid::Initialize ()
31 {
32     PlatformLinux::Initialize ();
33 
34     if (g_initialize_count++ == 0)
35     {
36 #if defined(__ANDROID__)
37         PlatformSP default_platform_sp (new PlatformAndroid(true));
38         default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
39         Platform::SetHostPlatform (default_platform_sp);
40 #endif
41         PluginManager::RegisterPlugin (PlatformAndroid::GetPluginNameStatic(false),
42                                        PlatformAndroid::GetPluginDescriptionStatic(false),
43                                        PlatformAndroid::CreateInstance);
44     }
45 }
46 
47 void
48 PlatformAndroid::Terminate ()
49 {
50     if (g_initialize_count > 0)
51     {
52         if (--g_initialize_count == 0)
53         {
54             PluginManager::UnregisterPlugin (PlatformAndroid::CreateInstance);
55         }
56     }
57 
58     PlatformLinux::Terminate ();
59 }
60 
61 PlatformSP
62 PlatformAndroid::CreateInstance (bool force, const ArchSpec *arch)
63 {
64     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
65     if (log)
66     {
67         const char *arch_name;
68         if (arch && arch->GetArchitectureName ())
69             arch_name = arch->GetArchitectureName ();
70         else
71             arch_name = "<null>";
72 
73         const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
74 
75         log->Printf ("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
76     }
77 
78     bool create = force;
79     if (create == false && arch && arch->IsValid())
80     {
81         const llvm::Triple &triple = arch->GetTriple();
82         switch (triple.getVendor())
83         {
84             case llvm::Triple::PC:
85                 create = true;
86                 break;
87 
88 #if defined(__ANDROID__)
89             // Only accept "unknown" for the vendor if the host is android and
90             // it "unknown" wasn't specified (it was just returned because it
91             // was NOT specified_
92             case llvm::Triple::VendorType::UnknownVendor:
93                 create = !arch->TripleVendorWasSpecified();
94                 break;
95 #endif
96             default:
97                 break;
98         }
99 
100         if (create)
101         {
102             switch (triple.getOS())
103             {
104                 case llvm::Triple::Android:
105                     break;
106 
107 #if defined(__ANDROID__)
108                 // Only accept "unknown" for the OS if the host is android and
109                 // it "unknown" wasn't specified (it was just returned because it
110                 // was NOT specified)
111                 case llvm::Triple::OSType::UnknownOS:
112                     create = !arch->TripleOSWasSpecified();
113                     break;
114 #endif
115                 default:
116                     create = false;
117                     break;
118             }
119         }
120     }
121 
122     if (create)
123     {
124         if (log)
125             log->Printf ("PlatformAndroid::%s() creating remote-android platform", __FUNCTION__);
126         return PlatformSP(new PlatformAndroid(false));
127     }
128 
129     if (log)
130         log->Printf ("PlatformAndroid::%s() aborting creation of remote-android platform", __FUNCTION__);
131 
132     return PlatformSP();
133 }
134 
135 PlatformAndroid::PlatformAndroid (bool is_host) :
136     PlatformLinux(is_host)
137 {
138 }
139 
140 PlatformAndroid::~PlatformAndroid()
141 {
142 }
143 
144 ConstString
145 PlatformAndroid::GetPluginNameStatic (bool is_host)
146 {
147     if (is_host)
148     {
149         static ConstString g_host_name(Platform::GetHostPlatformName ());
150         return g_host_name;
151     }
152     else
153     {
154         static ConstString g_remote_name("remote-android");
155         return g_remote_name;
156     }
157 }
158 
159 const char *
160 PlatformAndroid::GetPluginDescriptionStatic (bool is_host)
161 {
162     if (is_host)
163         return "Local Android user platform plug-in.";
164     else
165         return "Remote Android user platform plug-in.";
166 }
167 
168 ConstString
169 PlatformAndroid::GetPluginName()
170 {
171     return GetPluginNameStatic(IsHost());
172 }
173 
174 Error
175 PlatformAndroid::ConnectRemote(Args& args)
176 {
177     m_device_id.clear();
178 
179     if (IsHost())
180     {
181         return Error ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
182     }
183 
184     if (!m_remote_platform_sp)
185         m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
186 
187     int port;
188     std::string scheme, host, path;
189     const char *url = args.GetArgumentAtIndex(0);
190     if (!url)
191         return Error("URL is null.");
192     if (!UriParser::Parse(url, scheme, host, port, path))
193         return Error("Invalid URL: %s", url);
194     if (scheme == "adb")
195         m_device_id = host;
196 
197     auto error = PlatformLinux::ConnectRemote(args);
198     if (error.Success())
199     {
200         AdbClient adb;
201         error = AdbClient::CreateByDeviceID(m_device_id, adb);
202         if (error.Fail())
203             return error;
204 
205         m_device_id = adb.GetDeviceID();
206     }
207     return error;
208 }
209 
210 Error
211 PlatformAndroid::GetFile (const FileSpec& source,
212                           const FileSpec& destination)
213 {
214     if (IsHost() || !m_remote_platform_sp)
215         return PlatformLinux::GetFile(source, destination);
216 
217     FileSpec source_spec (source.GetPath (false), false, FileSpec::ePathSyntaxPosix);
218     if (source_spec.IsRelative())
219         source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false));
220 
221     AdbClient adb (m_device_id);
222     return adb.PullFile (source_spec, destination);
223 }
224 
225 Error
226 PlatformAndroid::PutFile (const FileSpec& source,
227                           const FileSpec& destination,
228                           uint32_t uid,
229                           uint32_t gid)
230 {
231     if (IsHost() || !m_remote_platform_sp)
232         return PlatformLinux::PutFile (source, destination, uid, gid);
233 
234     FileSpec destination_spec (destination.GetPath (false), false, FileSpec::ePathSyntaxPosix);
235     if (destination_spec.IsRelative())
236         destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false));
237 
238     AdbClient adb (m_device_id);
239     // TODO: Set correct uid and gid on remote file.
240     return adb.PushFile(source, destination_spec);
241 }
242 
243 const char *
244 PlatformAndroid::GetCacheHostname ()
245 {
246     return m_device_id.c_str ();
247 }
248 
249 Error
250 PlatformAndroid::DownloadModuleSlice (const FileSpec &src_file_spec,
251                                       const uint64_t src_offset,
252                                       const uint64_t src_size,
253                                       const FileSpec &dst_file_spec)
254 {
255     if (src_offset != 0)
256         return Error ("Invalid offset - %" PRIu64, src_offset);
257 
258     return GetFile (src_file_spec, dst_file_spec);
259 }
260