1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "../dumpsys.h" 18 19#include <vector> 20 21#include <gmock/gmock.h> 22#include <gtest/gtest.h> 23 24#include <android-base/file.h> 25#include <utils/String16.h> 26#include <utils/String8.h> 27#include <utils/Vector.h> 28 29using namespace android; 30 31using ::testing::_; 32using ::testing::Action; 33using ::testing::ActionInterface; 34using ::testing::DoAll; 35using ::testing::Eq; 36using ::testing::HasSubstr; 37using ::testing::MakeAction; 38using ::testing::Not; 39using ::testing::Return; 40using ::testing::StrEq; 41using ::testing::Test; 42using ::testing::WithArg; 43using ::testing::internal::CaptureStderr; 44using ::testing::internal::CaptureStdout; 45using ::testing::internal::GetCapturedStderr; 46using ::testing::internal::GetCapturedStdout; 47 48class ServiceManagerMock : public IServiceManager { 49 public: 50 MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&)); 51 MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&)); 52 MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool)); 53 MOCK_METHOD0(listServices, Vector<String16>()); 54 55 protected: 56 MOCK_METHOD0(onAsBinder, IBinder*()); 57}; 58 59class BinderMock : public BBinder { 60 public: 61 BinderMock() { 62 } 63 64 MOCK_METHOD2(dump, status_t(int, const Vector<String16>&)); 65}; 66 67// gmock black magic to provide a WithArg<0>(WriteOnFd(output)) matcher 68typedef void WriteOnFdFunction(int); 69 70class WriteOnFdAction : public ActionInterface<WriteOnFdFunction> { 71 public: 72 explicit WriteOnFdAction(const std::string& output) : output_(output) { 73 } 74 virtual Result Perform(const ArgumentTuple& args) { 75 int fd = ::std::tr1::get<0>(args); 76 android::base::WriteStringToFd(output_, fd); 77 } 78 79 private: 80 std::string output_; 81}; 82 83// Matcher used to emulate dump() by writing on its file descriptor. 84Action<WriteOnFdFunction> WriteOnFd(const std::string& output) { 85 return MakeAction(new WriteOnFdAction(output)); 86} 87 88// Matcher for args using Android's Vector<String16> format 89// TODO: move it to some common testing library 90MATCHER_P(AndroidElementsAre, expected, "") { 91 std::ostringstream errors; 92 if (arg.size() != expected.size()) { 93 errors << " sizes do not match (expected " << expected.size() << ", got " << arg.size() 94 << ")\n"; 95 } 96 int i = 0; 97 std::ostringstream actual_stream, expected_stream; 98 for (String16 actual : arg) { 99 std::string actual_str = String8(actual).c_str(); 100 std::string expected_str = expected[i]; 101 actual_stream << "'" << actual_str << "' "; 102 expected_stream << "'" << expected_str << "' "; 103 if (actual_str != expected_str) { 104 errors << " element mismatch at index " << i << "\n"; 105 } 106 i++; 107 } 108 109 if (!errors.str().empty()) { 110 errors << "\nExpected args: " << expected_stream.str() 111 << "\nActual args: " << actual_stream.str(); 112 *result_listener << errors.str(); 113 return false; 114 } 115 return true; 116} 117 118// Custom action to sleep for timeout seconds 119ACTION_P(Sleep, timeout) { 120 sleep(timeout); 121} 122 123class DumpsysTest : public Test { 124 public: 125 DumpsysTest() : sm_(), dump_(&sm_), stdout_(), stderr_() { 126 } 127 128 void ExpectListServices(std::vector<std::string> services) { 129 Vector<String16> services16; 130 for (auto& service : services) { 131 services16.add(String16(service.c_str())); 132 } 133 EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16)); 134 } 135 136 sp<BinderMock> ExpectCheckService(const char* name, bool running = true) { 137 sp<BinderMock> binder_mock; 138 if (running) { 139 binder_mock = new BinderMock; 140 } 141 EXPECT_CALL(sm_, checkService(String16(name))).WillRepeatedly(Return(binder_mock)); 142 return binder_mock; 143 } 144 145 void ExpectDump(const char* name, const std::string& output) { 146 sp<BinderMock> binder_mock = ExpectCheckService(name); 147 EXPECT_CALL(*binder_mock, dump(_, _)) 148 .WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0))); 149 } 150 151 void ExpectDumpWithArgs(const char* name, std::vector<std::string> args, 152 const std::string& output) { 153 sp<BinderMock> binder_mock = ExpectCheckService(name); 154 EXPECT_CALL(*binder_mock, dump(_, AndroidElementsAre(args))) 155 .WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0))); 156 } 157 158 void ExpectDumpAndHang(const char* name, int timeout_s, const std::string& output) { 159 sp<BinderMock> binder_mock = ExpectCheckService(name); 160 EXPECT_CALL(*binder_mock, dump(_, _)) 161 .WillRepeatedly(DoAll(Sleep(timeout_s), WithArg<0>(WriteOnFd(output)), Return(0))); 162 } 163 164 void CallMain(const std::vector<std::string>& args) { 165 const char* argv[1024] = {"/some/virtual/dir/dumpsys"}; 166 int argc = (int)args.size() + 1; 167 int i = 1; 168 for (const std::string& arg : args) { 169 argv[i++] = arg.c_str(); 170 } 171 CaptureStdout(); 172 CaptureStderr(); 173 int status = dump_.main(argc, const_cast<char**>(argv)); 174 stdout_ = GetCapturedStdout(); 175 stderr_ = GetCapturedStderr(); 176 EXPECT_THAT(status, Eq(0)); 177 } 178 179 void AssertRunningServices(const std::vector<std::string>& services) { 180 std::string expected("Currently running services:\n"); 181 for (const std::string& service : services) { 182 expected.append(" ").append(service).append("\n"); 183 } 184 EXPECT_THAT(stdout_, HasSubstr(expected)); 185 } 186 187 void AssertOutput(const std::string& expected) { 188 EXPECT_THAT(stdout_, StrEq(expected)); 189 } 190 191 void AssertOutputContains(const std::string& expected) { 192 EXPECT_THAT(stdout_, HasSubstr(expected)); 193 } 194 195 void AssertDumped(const std::string& service, const std::string& dump) { 196 EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump)); 197 } 198 199 void AssertNotDumped(const std::string& dump) { 200 EXPECT_THAT(stdout_, Not(HasSubstr(dump))); 201 } 202 203 void AssertStopped(const std::string& service) { 204 EXPECT_THAT(stderr_, HasSubstr("Can't find service: " + service + "\n")); 205 } 206 207 ServiceManagerMock sm_; 208 Dumpsys dump_; 209 210 private: 211 std::string stdout_, stderr_; 212}; 213 214// Tests 'dumpsys -l' when all services are running 215TEST_F(DumpsysTest, ListAllServices) { 216 ExpectListServices({"Locksmith", "Valet"}); 217 ExpectCheckService("Locksmith"); 218 ExpectCheckService("Valet"); 219 220 CallMain({"-l"}); 221 222 AssertRunningServices({"Locksmith", "Valet"}); 223} 224 225// Tests 'dumpsys -l' when a service is not running 226TEST_F(DumpsysTest, ListRunningServices) { 227 ExpectListServices({"Locksmith", "Valet"}); 228 ExpectCheckService("Locksmith"); 229 ExpectCheckService("Valet", false); 230 231 CallMain({"-l"}); 232 233 AssertRunningServices({"Locksmith"}); 234 AssertNotDumped({"Valet"}); 235} 236 237// Tests 'dumpsys service_name' on a service is running 238TEST_F(DumpsysTest, DumpRunningService) { 239 ExpectDump("Valet", "Here's your car"); 240 241 CallMain({"Valet"}); 242 243 AssertOutput("Here's your car"); 244} 245 246// Tests 'dumpsys -t 1 service_name' on a service that times out after 2s 247TEST_F(DumpsysTest, DumpRunningServiceTimeout) { 248 ExpectDumpAndHang("Valet", 2, "Here's your car"); 249 250 CallMain({"-t", "1", "Valet"}); 251 252 AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED"); 253 AssertNotDumped("Here's your car"); 254 255 // Must wait so binder mock is deleted, otherwise test will fail with a leaked object 256 sleep(1); 257} 258 259// Tests 'dumpsys service_name Y U NO HAVE ARGS' on a service that is running 260TEST_F(DumpsysTest, DumpWithArgsRunningService) { 261 ExpectDumpWithArgs("SERVICE", {"Y", "U", "NO", "HANDLE", "ARGS"}, "I DO!"); 262 263 CallMain({"SERVICE", "Y", "U", "NO", "HANDLE", "ARGS"}); 264 265 AssertOutput("I DO!"); 266} 267 268// Tests 'dumpsys' with no arguments 269TEST_F(DumpsysTest, DumpMultipleServices) { 270 ExpectListServices({"running1", "stopped2", "running3"}); 271 ExpectDump("running1", "dump1"); 272 ExpectCheckService("stopped2", false); 273 ExpectDump("running3", "dump3"); 274 275 CallMain({}); 276 277 AssertRunningServices({"running1", "running3"}); 278 AssertDumped("running1", "dump1"); 279 AssertStopped("stopped2"); 280 AssertDumped("running3", "dump3"); 281} 282 283// Tests 'dumpsys --skip skipped3 skipped5', which should skip these services 284TEST_F(DumpsysTest, DumpWithSkip) { 285 ExpectListServices({"running1", "stopped2", "skipped3", "running4", "skipped5"}); 286 ExpectDump("running1", "dump1"); 287 ExpectCheckService("stopped2", false); 288 ExpectDump("skipped3", "dump3"); 289 ExpectDump("running4", "dump4"); 290 ExpectDump("skipped5", "dump5"); 291 292 CallMain({"--skip", "skipped3", "skipped5"}); 293 294 AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"}); 295 AssertDumped("running1", "dump1"); 296 AssertDumped("running4", "dump4"); 297 AssertStopped("stopped2"); 298 AssertNotDumped("dump3"); 299 AssertNotDumped("dump5"); 300} 301