Skip to content

Commit 49f55b0

Browse files
committed
[lldb][Android] Add PlatformAndroidTest
To test D152759 [lldb][Android] Support zip .so file introduce PlatformAndroidTest with the capability of mocking adb client. Differential Revision: https://reviews.llvm.org/D152855
1 parent cdbdf93 commit 49f55b0

File tree

5 files changed

+219
-24
lines changed

5 files changed

+219
-24
lines changed

lldb/source/Plugins/Platform/Android/AdbClient.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,22 @@ class AdbClient {
3636
friend class AdbClient;
3737

3838
public:
39-
~SyncService();
39+
virtual ~SyncService();
4040

41-
Status PullFile(const FileSpec &remote_file, const FileSpec &local_file);
41+
virtual Status PullFile(const FileSpec &remote_file,
42+
const FileSpec &local_file);
4243

4344
Status PushFile(const FileSpec &local_file, const FileSpec &remote_file);
4445

45-
Status Stat(const FileSpec &remote_file, uint32_t &mode, uint32_t &size,
46-
uint32_t &mtime);
46+
virtual Status Stat(const FileSpec &remote_file, uint32_t &mode,
47+
uint32_t &size, uint32_t &mtime);
4748

4849
bool IsConnected() const;
4950

50-
private:
51+
protected:
5152
explicit SyncService(std::unique_ptr<Connection> &&conn);
5253

54+
private:
5355
Status SendSyncRequest(const char *request_id, const uint32_t data_len,
5456
const void *data);
5557

@@ -78,7 +80,7 @@ class AdbClient {
7880
AdbClient();
7981
explicit AdbClient(const std::string &device_id);
8082

81-
~AdbClient();
83+
virtual ~AdbClient();
8284

8385
const std::string &GetDeviceID() const;
8486

@@ -96,10 +98,11 @@ class AdbClient {
9698
Status Shell(const char *command, std::chrono::milliseconds timeout,
9799
std::string *output);
98100

99-
Status ShellToFile(const char *command, std::chrono::milliseconds timeout,
100-
const FileSpec &output_file_spec);
101+
virtual Status ShellToFile(const char *command,
102+
std::chrono::milliseconds timeout,
103+
const FileSpec &output_file_spec);
101104

102-
std::unique_ptr<SyncService> GetSyncService(Status &error);
105+
virtual std::unique_ptr<SyncService> GetSyncService(Status &error);
103106

104107
Status SwitchDeviceTransport();
105108

lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,14 @@ Status PlatformAndroid::GetFile(const FileSpec &source,
201201

202202
// mode == 0 can signify that adbd cannot access the file due security
203203
// constraints - try "cat ..." as a fallback.
204-
AdbClient adb(m_device_id);
204+
AdbClientUP adb(GetAdbClient(error));
205+
if (error.Fail())
206+
return error;
205207

206208
char cmd[PATH_MAX];
207209
snprintf(cmd, sizeof(cmd), "cat '%s'", source_file.c_str());
208210

209-
return adb.ShellToFile(cmd, minutes(1), destination);
211+
return adb->ShellToFile(cmd, minutes(1), destination);
210212
}
211213

212214
Status PlatformAndroid::PutFile(const FileSpec &source,
@@ -250,7 +252,10 @@ Status PlatformAndroid::DownloadModuleSlice(const FileSpec &src_file_spec,
250252
if (pos != std::string::npos)
251253
source_file = source_file.substr(0, pos);
252254

253-
AdbClient adb(m_device_id);
255+
Status error;
256+
AdbClientUP adb(GetAdbClient(error));
257+
if (error.Fail())
258+
return error;
254259

255260
// Use 'shell dd' to download the file slice with the offset and size.
256261
char cmd[PATH_MAX];
@@ -259,7 +264,7 @@ Status PlatformAndroid::DownloadModuleSlice(const FileSpec &src_file_spec,
259264
"skip=%" PRIu64 " count=%" PRIu64 " status=none",
260265
source_file.c_str(), src_offset, src_size);
261266

262-
return adb.ShellToFile(cmd, minutes(1), dst_file_spec);
267+
return adb->ShellToFile(cmd, minutes(1), dst_file_spec);
263268
}
264269

265270
Status PlatformAndroid::DisconnectRemote() {
@@ -283,9 +288,12 @@ uint32_t PlatformAndroid::GetSdkVersion() {
283288
return m_sdk_version;
284289

285290
std::string version_string;
286-
AdbClient adb(m_device_id);
287-
Status error =
288-
adb.Shell("getprop ro.build.version.sdk", seconds(5), &version_string);
291+
Status error;
292+
AdbClientUP adb(GetAdbClient(error));
293+
if (error.Fail())
294+
return 0;
295+
error =
296+
adb->Shell("getprop ro.build.version.sdk", seconds(5), &version_string);
289297
version_string = llvm::StringRef(version_string).trim().str();
290298

291299
if (error.Fail() || version_string.empty()) {
@@ -321,10 +329,13 @@ Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
321329
nullptr)
322330
return Status("Symtab already available in the module");
323331

324-
AdbClient adb(m_device_id);
332+
Status error;
333+
AdbClientUP adb(GetAdbClient(error));
334+
if (error.Fail())
335+
return error;
325336
std::string tmpdir;
326-
Status error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp",
327-
seconds(5), &tmpdir);
337+
error = adb->Shell("mktemp --directory --tmpdir /data/local/tmp", seconds(5),
338+
&tmpdir);
328339
if (error.Fail() || tmpdir.empty())
329340
return Status("Failed to generate temporary directory on the device (%s)",
330341
error.AsCString());
@@ -335,7 +346,7 @@ Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
335346
tmpdir_remover(&tmpdir, [&adb](std::string *s) {
336347
StreamString command;
337348
command.Printf("rm -rf %s", s->c_str());
338-
Status error = adb.Shell(command.GetData(), seconds(5), nullptr);
349+
Status error = adb->Shell(command.GetData(), seconds(5), nullptr);
339350

340351
Log *log = GetLog(LLDBLog::Platform);
341352
if (log && error.Fail())
@@ -351,7 +362,7 @@ Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
351362
command.Printf("oatdump --symbolize=%s --output=%s",
352363
module_sp->GetPlatformFileSpec().GetPath(false).c_str(),
353364
symfile_platform_filespec.GetPath(false).c_str());
354-
error = adb.Shell(command.GetData(), minutes(1), nullptr);
365+
error = adb->Shell(command.GetData(), minutes(1), nullptr);
355366
if (error.Fail())
356367
return Status("Oatdump failed: %s", error.AsCString());
357368

@@ -390,11 +401,22 @@ PlatformAndroid::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
390401
return PlatformPOSIX::GetLibdlFunctionDeclarations(process);
391402
}
392403

404+
PlatformAndroid::AdbClientUP PlatformAndroid::GetAdbClient(Status &error) {
405+
AdbClientUP adb(std::make_unique<AdbClient>(m_device_id));
406+
if (adb)
407+
error.Clear();
408+
else
409+
error = Status("Failed to create AdbClient");
410+
return adb;
411+
}
412+
393413
AdbClient::SyncService *PlatformAndroid::GetSyncService(Status &error) {
394414
if (m_adb_sync_svc && m_adb_sync_svc->IsConnected())
395415
return m_adb_sync_svc.get();
396416

397-
AdbClient adb(m_device_id);
398-
m_adb_sync_svc = adb.GetSyncService(error);
417+
AdbClientUP adb(GetAdbClient(error));
418+
if (error.Fail())
419+
return nullptr;
420+
m_adb_sync_svc = adb->GetSyncService(error);
399421
return (error.Success()) ? m_adb_sync_svc.get() : nullptr;
400422
}

lldb/source/Plugins/Platform/Android/PlatformAndroid.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class PlatformAndroid : public platform_linux::PlatformLinux {
7070
llvm::StringRef
7171
GetLibdlFunctionDeclarations(lldb_private::Process *process) override;
7272

73+
typedef std::unique_ptr<AdbClient> AdbClientUP;
74+
virtual AdbClientUP GetAdbClient(Status &error);
75+
7376
private:
7477
AdbClient::SyncService *GetSyncService(Status &error);
7578

@@ -78,7 +81,7 @@ class PlatformAndroid : public platform_linux::PlatformLinux {
7881
uint32_t m_sdk_version;
7982
};
8083

81-
} // namespace platofor_android
84+
} // namespace platform_android
8285
} // namespace lldb_private
8386

8487
#endif // LLDB_SOURCE_PLUGINS_PLATFORM_ANDROID_PLATFORMANDROID_H

lldb/unittests/Platform/Android/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Platform/Android)
22

33
add_lldb_unittest(AdbClientTests
44
AdbClientTest.cpp
5+
PlatformAndroidTest.cpp
56

67
LINK_LIBS
78
lldbPluginPlatformAndroid
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
//===-- PlatformAndroidTest.cpp -------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "Plugins/Platform/Android/PlatformAndroid.h"
10+
#include "Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h"
11+
#include "TestingSupport/SubsystemRAII.h"
12+
#include "TestingSupport/TestUtilities.h"
13+
#include "lldb/Utility/Connection.h"
14+
#include "gmock/gmock.h"
15+
16+
using namespace lldb;
17+
using namespace lldb_private;
18+
using namespace lldb_private::platform_android;
19+
using namespace testing;
20+
21+
namespace {
22+
23+
class MockSyncService : public AdbClient::SyncService {
24+
public:
25+
MockSyncService() : SyncService(std::unique_ptr<Connection>()) {}
26+
27+
MOCK_METHOD2(PullFile,
28+
Status(const FileSpec &remote_file, const FileSpec &local_file));
29+
MOCK_METHOD4(Stat, Status(const FileSpec &remote_file, uint32_t &mode,
30+
uint32_t &size, uint32_t &mtime));
31+
};
32+
33+
typedef std::unique_ptr<AdbClient::SyncService> SyncServiceUP;
34+
35+
class MockAdbClient : public AdbClient {
36+
public:
37+
explicit MockAdbClient() : AdbClient("mock") {}
38+
39+
MOCK_METHOD3(ShellToFile,
40+
Status(const char *command, std::chrono::milliseconds timeout,
41+
const FileSpec &output_file_spec));
42+
MOCK_METHOD1(GetSyncService, SyncServiceUP(Status &error));
43+
};
44+
45+
class PlatformAndroidTest : public PlatformAndroid, public ::testing::Test {
46+
public:
47+
PlatformAndroidTest() : PlatformAndroid(false) {
48+
m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
49+
}
50+
51+
MOCK_METHOD1(GetAdbClient, AdbClientUP(Status &error));
52+
};
53+
54+
} // namespace
55+
56+
TEST_F(PlatformAndroidTest, DownloadModuleSliceWithAdbClientError) {
57+
EXPECT_CALL(*this, GetAdbClient(_))
58+
.Times(1)
59+
.WillOnce(DoAll(WithArg<0>([](auto &arg) {
60+
arg = Status("Failed to create AdbClient");
61+
}),
62+
Return(ByMove(AdbClientUP()))));
63+
64+
EXPECT_TRUE(
65+
DownloadModuleSlice(
66+
FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,
67+
3600, FileSpec())
68+
.Fail());
69+
}
70+
71+
TEST_F(PlatformAndroidTest, DownloadModuleSliceWithNormalFile) {
72+
auto sync_service = new MockSyncService();
73+
EXPECT_CALL(*sync_service, Stat(FileSpec("/system/lib64/libc.so"), _, _, _))
74+
.Times(1)
75+
.WillOnce(DoAll(SetArgReferee<1>(1), Return(Status())));
76+
EXPECT_CALL(*sync_service, PullFile(FileSpec("/system/lib64/libc.so"), _))
77+
.Times(1)
78+
.WillOnce(Return(Status()));
79+
80+
auto adb_client = new MockAdbClient();
81+
EXPECT_CALL(*adb_client, GetSyncService(_))
82+
.Times(1)
83+
.WillOnce(Return(ByMove(SyncServiceUP(sync_service))));
84+
85+
EXPECT_CALL(*this, GetAdbClient(_))
86+
.Times(1)
87+
.WillOnce(Return(ByMove(AdbClientUP(adb_client))));
88+
89+
EXPECT_TRUE(
90+
DownloadModuleSlice(FileSpec("/system/lib64/libc.so"), 0, 0, FileSpec())
91+
.Success());
92+
}
93+
94+
TEST_F(PlatformAndroidTest, DownloadModuleSliceWithZipFile) {
95+
auto adb_client = new MockAdbClient();
96+
EXPECT_CALL(*adb_client,
97+
ShellToFile(StrEq("dd if='/system/app/Test/Test.apk' "
98+
"iflag=skip_bytes,count_bytes "
99+
"skip=4096 count=3600 status=none"),
100+
_, _))
101+
.Times(1)
102+
.WillOnce(Return(Status()));
103+
104+
EXPECT_CALL(*this, GetAdbClient(_))
105+
.Times(1)
106+
.WillOnce(Return(ByMove(AdbClientUP(adb_client))));
107+
108+
EXPECT_TRUE(
109+
DownloadModuleSlice(
110+
FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,
111+
3600, FileSpec())
112+
.Success());
113+
}
114+
115+
TEST_F(PlatformAndroidTest, GetFileWithNormalFile) {
116+
auto sync_service = new MockSyncService();
117+
EXPECT_CALL(*sync_service, Stat(FileSpec("/data/local/tmp/test"), _, _, _))
118+
.Times(1)
119+
.WillOnce(DoAll(SetArgReferee<1>(1), Return(Status())));
120+
EXPECT_CALL(*sync_service, PullFile(FileSpec("/data/local/tmp/test"), _))
121+
.Times(1)
122+
.WillOnce(Return(Status()));
123+
124+
auto adb_client = new MockAdbClient();
125+
EXPECT_CALL(*adb_client, GetSyncService(_))
126+
.Times(1)
127+
.WillOnce(Return(ByMove(SyncServiceUP(sync_service))));
128+
129+
EXPECT_CALL(*this, GetAdbClient(_))
130+
.Times(1)
131+
.WillOnce(Return(ByMove(AdbClientUP(adb_client))));
132+
133+
EXPECT_TRUE(GetFile(FileSpec("/data/local/tmp/test"), FileSpec()).Success());
134+
}
135+
136+
TEST_F(PlatformAndroidTest, GetFileWithCatFallback) {
137+
auto sync_service = new MockSyncService();
138+
EXPECT_CALL(
139+
*sync_service,
140+
Stat(FileSpec("/data/data/com.example.app/lib-main/libtest.so"), _, _, _))
141+
.Times(1)
142+
.WillOnce(DoAll(SetArgReferee<1>(0), Return(Status())));
143+
144+
auto adb_client0 = new MockAdbClient();
145+
EXPECT_CALL(*adb_client0, GetSyncService(_))
146+
.Times(1)
147+
.WillOnce(Return(ByMove(SyncServiceUP(sync_service))));
148+
149+
auto adb_client1 = new MockAdbClient();
150+
EXPECT_CALL(
151+
*adb_client1,
152+
ShellToFile(StrEq("cat '/data/data/com.example.app/lib-main/libtest.so'"),
153+
_, _))
154+
.Times(1)
155+
.WillOnce(Return(Status()));
156+
157+
EXPECT_CALL(*this, GetAdbClient(_))
158+
.Times(2)
159+
.WillOnce(Return(ByMove(AdbClientUP(adb_client0))))
160+
.WillOnce(Return(ByMove(AdbClientUP(adb_client1))));
161+
162+
EXPECT_TRUE(
163+
GetFile(FileSpec("/data/data/com.example.app/lib-main/libtest.so"),
164+
FileSpec())
165+
.Success());
166+
}

0 commit comments

Comments
 (0)