299 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "Plugins/Platform/Android/PlatformAndroid.h"10#include "Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h"11#include "lldb/Utility/Connection.h"12#include "gmock/gmock.h"13 14using namespace lldb;15using namespace lldb_private;16using namespace lldb_private::platform_android;17using namespace testing;18 19namespace {20 21class MockAdbClient : public AdbClient {22public:23 explicit MockAdbClient() : AdbClient() {}24 25 MOCK_METHOD3(ShellToFile,26 Status(const char *command, std::chrono::milliseconds timeout,27 const FileSpec &output_file_spec));28};29 30class PlatformAndroidTest : public PlatformAndroid, public ::testing::Test {31public:32 PlatformAndroidTest() : PlatformAndroid(false) {33 m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());34 35 // Set up default mock behavior to avoid uninteresting call warnings36 ON_CALL(*this, GetSyncService(_))37 .WillByDefault([](Status &error) -> std::unique_ptr<AdbSyncService> {38 error = Status::FromErrorString("Sync service unavailable");39 return nullptr;40 });41 }42 43 MOCK_METHOD1(GetAdbClient, AdbClientUP(Status &error));44 MOCK_METHOD0(GetPropertyPackageName, llvm::StringRef());45 MOCK_METHOD1(GetSyncService, std::unique_ptr<AdbSyncService>(Status &error));46 47 // Make GetSyncService public for testing48 using PlatformAndroid::GetSyncService;49};50 51} // namespace52 53TEST_F(PlatformAndroidTest,54 DownloadModuleSlice_AdbClientError_FailsGracefully) {55 EXPECT_CALL(*this, GetAdbClient(_))56 .WillOnce(DoAll(WithArg<0>([](auto &arg) {57 arg = Status::FromErrorString(58 "Failed to create AdbClient");59 }),60 Return(ByMove(AdbClientUP()))));61 62 Status result = DownloadModuleSlice(63 FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,64 3600, FileSpec("/tmp/libtest.so"));65 66 EXPECT_TRUE(result.Fail());67 EXPECT_THAT(result.AsCString(), HasSubstr("Failed to create AdbClient"));68}69 70TEST_F(PlatformAndroidTest, DownloadModuleSlice_ZipFile_UsesCorrectDdCommand) {71 auto *adb_client = new MockAdbClient();72 EXPECT_CALL(*adb_client,73 ShellToFile(StrEq("dd if='/system/app/Test/Test.apk' "74 "iflag=skip_bytes,count_bytes "75 "skip=4096 count=3600 status=none"),76 _, _))77 .WillOnce(Return(Status()));78 79 EXPECT_CALL(*this, GetPropertyPackageName())80 .WillOnce(Return(llvm::StringRef("")));81 82 EXPECT_CALL(*this, GetAdbClient(_))83 .WillOnce(Return(ByMove(AdbClientUP(adb_client))));84 85 Status result = DownloadModuleSlice(86 FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,87 3600, FileSpec("/tmp/libtest.so"));88 89 EXPECT_TRUE(result.Success());90}91 92TEST_F(PlatformAndroidTest,93 DownloadModuleSlice_ZipFileWithRunAs_UsesRunAsCommand) {94 auto *adb_client = new MockAdbClient();95 EXPECT_CALL(*adb_client,96 ShellToFile(StrEq("run-as 'com.example.test' "97 "dd if='/system/app/Test/Test.apk' "98 "iflag=skip_bytes,count_bytes "99 "skip=4096 count=3600 status=none"),100 _, _))101 .WillOnce(Return(Status()));102 103 EXPECT_CALL(*this, GetPropertyPackageName())104 .WillOnce(Return(llvm::StringRef("com.example.test")));105 106 EXPECT_CALL(*this, GetAdbClient(_))107 .WillOnce(Return(ByMove(AdbClientUP(adb_client))));108 109 Status result = DownloadModuleSlice(110 FileSpec("/system/app/Test/Test.apk!/lib/arm64-v8a/libtest.so"), 4096,111 3600, FileSpec("/tmp/libtest.so"));112 113 EXPECT_TRUE(result.Success());114}115 116TEST_F(PlatformAndroidTest,117 DownloadModuleSlice_LargeFile_CalculatesParametersCorrectly) {118 const uint64_t large_offset = 100 * 1024 * 1024; // 100MB offset119 const uint64_t large_size = 50 * 1024 * 1024; // 50MB size120 121 auto *adb_client = new MockAdbClient();122 EXPECT_CALL(*adb_client,123 ShellToFile(StrEq("dd if='/system/app/Large.apk' "124 "iflag=skip_bytes,count_bytes "125 "skip=104857600 count=52428800 status=none"),126 _, _))127 .WillOnce(Return(Status()));128 129 EXPECT_CALL(*this, GetPropertyPackageName())130 .WillOnce(Return(llvm::StringRef("")));131 132 EXPECT_CALL(*this, GetAdbClient(_))133 .WillOnce(Return(ByMove(AdbClientUP(adb_client))));134 135 Status result = DownloadModuleSlice(136 FileSpec("/system/app/Large.apk!/lib/arm64-v8a/large.so"), large_offset,137 large_size, FileSpec("/tmp/large.so"));138 139 EXPECT_TRUE(result.Success());140}141 142TEST_F(PlatformAndroidTest,143 GetFile_SyncServiceUnavailable_FallsBackToShellCat) {144 auto *adb_client = new MockAdbClient();145 EXPECT_CALL(*adb_client,146 ShellToFile(StrEq("cat '/data/local/tmp/test'"), _, _))147 .WillOnce(Return(Status()));148 149 EXPECT_CALL(*this, GetPropertyPackageName())150 .WillOnce(Return(llvm::StringRef("")));151 152 EXPECT_CALL(*this, GetAdbClient(_))153 .WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),154 Return(ByMove(AdbClientUP(adb_client)))));155 156 EXPECT_CALL(*this, GetSyncService(_))157 .WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {158 error = Status::FromErrorString("Sync service unavailable");159 return nullptr;160 });161 162 Status result =163 GetFile(FileSpec("/data/local/tmp/test"), FileSpec("/tmp/test"));164 EXPECT_TRUE(result.Success());165}166 167TEST_F(PlatformAndroidTest, GetFile_WithRunAs_UsesRunAsInShellCommand) {168 auto *adb_client = new MockAdbClient();169 EXPECT_CALL(170 *adb_client,171 ShellToFile(StrEq("run-as 'com.example.app' "172 "cat '/data/data/com.example.app/lib-main/libtest.so'"),173 _, _))174 .WillOnce(Return(Status()));175 176 EXPECT_CALL(*this, GetPropertyPackageName())177 .WillOnce(Return(llvm::StringRef("com.example.app")));178 179 EXPECT_CALL(*this, GetAdbClient(_))180 .WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),181 Return(ByMove(AdbClientUP(adb_client)))));182 183 EXPECT_CALL(*this, GetSyncService(_))184 .WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {185 error = Status::FromErrorString("Sync service unavailable");186 return nullptr;187 });188 189 Status result =190 GetFile(FileSpec("/data/data/com.example.app/lib-main/libtest.so"),191 FileSpec("/tmp/libtest.so"));192 EXPECT_TRUE(result.Success());193}194 195TEST_F(PlatformAndroidTest, GetFile_FilenameWithSingleQuotes_Rejected) {196 EXPECT_CALL(*this, GetSyncService(_))197 .WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {198 error = Status::FromErrorString("Sync service unavailable");199 return nullptr;200 });201 202 Status result =203 GetFile(FileSpec("/test/file'with'quotes"), FileSpec("/tmp/output"));204 205 EXPECT_TRUE(result.Fail());206 EXPECT_THAT(result.AsCString(), HasSubstr("single-quotes"));207}208 209TEST_F(PlatformAndroidTest,210 DownloadModuleSlice_FilenameWithSingleQuotes_Rejected) {211 Status result = DownloadModuleSlice(FileSpec("/test/file'with'quotes"), 100,212 200, FileSpec("/tmp/output"));213 214 EXPECT_TRUE(result.Fail());215 EXPECT_THAT(result.AsCString(), HasSubstr("single-quotes"));216}217 218TEST_F(PlatformAndroidTest, GetFile_NetworkTimeout_PropagatesErrorCorrectly) {219 auto *adb_client = new MockAdbClient();220 EXPECT_CALL(*adb_client, ShellToFile(_, _, _))221 .WillOnce(Return(Status::FromErrorString("Network timeout")));222 223 EXPECT_CALL(*this, GetPropertyPackageName())224 .WillOnce(Return(llvm::StringRef("")));225 226 EXPECT_CALL(*this, GetAdbClient(_))227 .WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),228 Return(ByMove(AdbClientUP(adb_client)))));229 230 EXPECT_CALL(*this, GetSyncService(_))231 .WillOnce([](Status &error) -> std::unique_ptr<AdbSyncService> {232 error = Status::FromErrorString("Sync service unavailable");233 return nullptr;234 });235 236 Status result =237 GetFile(FileSpec("/data/large/file.so"), FileSpec("/tmp/large.so"));238 EXPECT_TRUE(result.Fail());239 EXPECT_THAT(result.AsCString(), HasSubstr("Network timeout"));240}241 242TEST_F(PlatformAndroidTest, SyncService_ConnectionFailsGracefully) {243 // Constructor should succeed even with a failing connection244 AdbSyncService sync_service("test-device");245 246 // The service should report as not connected initially247 EXPECT_FALSE(sync_service.IsConnected());248 EXPECT_EQ(sync_service.GetDeviceId(), "test-device");249 250 // Operations should fail gracefully when connection setup fails251 FileSpec remote_file("/data/test.txt");252 FileSpec local_file("/tmp/test.txt");253 uint32_t mode, size, mtime;254 255 Status result = sync_service.Stat(remote_file, mode, size, mtime);256 EXPECT_TRUE(result.Fail());257}258 259TEST_F(PlatformAndroidTest, GetRunAs_FormatsPackageNameCorrectly) {260 // Empty package name261 EXPECT_CALL(*this, GetPropertyPackageName())262 .WillOnce(Return(llvm::StringRef("")));263 EXPECT_EQ(this->GetRunAs(), "");264 265 // Valid package name266 EXPECT_CALL(*this, GetPropertyPackageName())267 .WillOnce(Return(llvm::StringRef("com.example.test")));268 EXPECT_EQ(this->GetRunAs(), "run-as 'com.example.test' ");269}270 271TEST_F(PlatformAndroidTest,272 DownloadModuleSlice_ZeroOffset_CallsGetFileInsteadOfDd) {273 // When offset=0, DownloadModuleSlice calls GetFile which uses 'cat', not 'dd'274 // We need to ensure the sync service fails so GetFile falls back to shell cat275 auto *adb_client = new MockAdbClient();276 EXPECT_CALL(*adb_client,277 ShellToFile(StrEq("cat '/system/lib64/libc.so'"), _, _))278 .WillOnce(Return(Status()));279 280 EXPECT_CALL(*this, GetPropertyPackageName())281 .WillOnce(Return(llvm::StringRef("")));282 283 EXPECT_CALL(*this, GetAdbClient(_))284 .WillOnce(DoAll(WithArg<0>([](auto &arg) { arg.Clear(); }),285 Return(ByMove(AdbClientUP(adb_client)))));286 287 // Mock GetSyncService to fail, forcing GetFile to use shell cat fallback288 EXPECT_CALL(*this, GetSyncService(_))289 .WillOnce(DoAll(WithArg<0>([](auto &arg) {290 arg =291 Status::FromErrorString("Sync service unavailable");292 }),293 Return(ByMove(std::unique_ptr<AdbSyncService>()))));294 295 Status result = DownloadModuleSlice(FileSpec("/system/lib64/libc.so"), 0, 0,296 FileSpec("/tmp/libc.so"));297 EXPECT_TRUE(result.Success());298}299