• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 <sysexits.h>
18 #include <unistd.h>
19 
20 #include <iostream>
21 #include <string>
22 
23 #include <android-base/file.h>
24 #include <android-base/logging.h>
25 #include <android-base/strings.h>
26 #include <android/hardware/health/2.1/IHealth.h>
27 #include <gmock/gmock.h>
28 #include <gtest/gtest.h>
29 #include <health/utils.h>
30 
31 #include "healthd_mode_charger_hidl.h"
32 
33 using android::hardware::Return;
34 using android::hardware::health::InitHealthdConfig;
35 using std::string_literals::operator""s;
36 using testing::_;
37 using testing::Invoke;
38 using testing::NiceMock;
39 using testing::StrEq;
40 using testing::Test;
41 
42 namespace android {
43 
44 // A replacement to ASSERT_* to be used in a forked process. When the condition is not met,
45 // print a gtest message, then exit abnormally.
46 class ChildAssertHelper : public std::stringstream {
47   public:
ChildAssertHelper(bool res,const char * expr,const char * file,int line)48     ChildAssertHelper(bool res, const char* expr, const char* file, int line) : res_(res) {
49         (*this) << file << ":" << line << ": `" << expr << "` evaluates to false\n";
50     }
~ChildAssertHelper()51     ~ChildAssertHelper() {
52         EXPECT_TRUE(res_) << str();
53         if (!res_) exit(EX_SOFTWARE);
54     }
55 
56   private:
57     bool res_;
58     DISALLOW_COPY_AND_ASSIGN(ChildAssertHelper);
59 };
60 #define CHILD_ASSERT_TRUE(expr) ChildAssertHelper(expr, #expr, __FILE__, __LINE__)
61 
62 // Run |test_body| in a chroot jail in a forked process. |subdir| is a sub-directory in testdata.
63 // Within |test_body|,
64 // - non-fatal errors may be reported using EXPECT_* macro as usual.
65 // - fatal errors must be reported using CHILD_ASSERT_TRUE macro. ASSERT_* must not be used.
ForkTest(const std::string & subdir,const std::function<void (void)> & test_body)66 void ForkTest(const std::string& subdir, const std::function<void(void)>& test_body) {
67     pid_t pid = fork();
68     ASSERT_GE(pid, 0) << "Fork fails: " << strerror(errno);
69     if (pid == 0) {
70         // child
71         CHILD_ASSERT_TRUE(
72                 chroot((android::base::GetExecutableDirectory() + "/" + subdir).c_str()) != -1)
73                 << "Failed to chroot to " << subdir << ": " << strerror(errno);
74         test_body();
75         // EXPECT_* macros may set the HasFailure bit without calling exit(). Set exit status
76         // accordingly.
77         exit(::testing::Test::HasFailure() ? EX_SOFTWARE : EX_OK);
78     }
79     // parent
80     int status;
81     ASSERT_NE(-1, waitpid(pid, &status, 0)) << "waitpid() fails: " << strerror(errno);
82     ASSERT_TRUE(WIFEXITED(status)) << "Test fails, waitpid() returns " << status;
83     ASSERT_EQ(EX_OK, WEXITSTATUS(status)) << "Test fails, child process returns " << status;
84 }
85 
86 class MockHealth : public android::hardware::health::V2_1::IHealth {
87     MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, registerCallback,
88                 (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
89     MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, unregisterCallback,
90                 (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
91     MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, update, ());
92     MOCK_METHOD(Return<void>, getChargeCounter, (getChargeCounter_cb _hidl_cb));
93     MOCK_METHOD(Return<void>, getCurrentNow, (getCurrentNow_cb _hidl_cb));
94     MOCK_METHOD(Return<void>, getCurrentAverage, (getCurrentAverage_cb _hidl_cb));
95     MOCK_METHOD(Return<void>, getCapacity, (getCapacity_cb _hidl_cb));
96     MOCK_METHOD(Return<void>, getEnergyCounter, (getEnergyCounter_cb _hidl_cb));
97     MOCK_METHOD(Return<void>, getChargeStatus, (getChargeStatus_cb _hidl_cb));
98     MOCK_METHOD(Return<void>, getStorageInfo, (getStorageInfo_cb _hidl_cb));
99     MOCK_METHOD(Return<void>, getDiskStats, (getDiskStats_cb _hidl_cb));
100     MOCK_METHOD(Return<void>, getHealthInfo, (getHealthInfo_cb _hidl_cb));
101     MOCK_METHOD(Return<void>, getHealthConfig, (getHealthConfig_cb _hidl_cb));
102     MOCK_METHOD(Return<void>, getHealthInfo_2_1, (getHealthInfo_2_1_cb _hidl_cb));
103     MOCK_METHOD(Return<void>, shouldKeepScreenOn, (shouldKeepScreenOn_cb _hidl_cb));
104 };
105 
106 class TestCharger : public ChargerHidl {
107   public:
108     // Inherit constructor.
109     using ChargerHidl::ChargerHidl;
110     // Expose protected functions to be used in tests.
Init(struct healthd_config * config)111     void Init(struct healthd_config* config) override { ChargerHidl::Init(config); }
112     MOCK_METHOD(int, CreateDisplaySurface, (const std::string& name, GRSurface** surface));
113     MOCK_METHOD(int, CreateMultiDisplaySurface,
114                 (const std::string& name, int* frames, int* fps, GRSurface*** surface));
115 };
116 
117 // Intentionally leak TestCharger instance to avoid calling ~HealthLoop() because ~HealthLoop()
118 // should never be called. But still verify expected calls upon destruction.
119 class VerifiedTestCharger {
120   public:
VerifiedTestCharger(TestCharger * charger)121     VerifiedTestCharger(TestCharger* charger) : charger_(charger) {
122         testing::Mock::AllowLeak(charger_);
123     }
operator *()124     TestCharger& operator*() { return *charger_; }
operator ->()125     TestCharger* operator->() { return charger_; }
~VerifiedTestCharger()126     ~VerifiedTestCharger() { testing::Mock::VerifyAndClearExpectations(charger_); }
127 
128   private:
129     TestCharger* charger_;
130 };
131 
132 // Do not use SetUp and TearDown of a test suite, as they will be invoked in the parent process, not
133 // the child process. In particular, if the test suite contains mocks, they will not be verified in
134 // the child process. Instead, create mocks within closures in each tests.
ExpectChargerResAt(const std::string & root)135 void ExpectChargerResAt(const std::string& root) {
136     sp<NiceMock<MockHealth>> health(new NiceMock<MockHealth>());
137     VerifiedTestCharger charger(new NiceMock<TestCharger>(health));
138 
139     // Only one frame in all testdata/**/animation.txt
140     GRSurface* multi[] = {nullptr};
141 
142     EXPECT_CALL(*charger, CreateDisplaySurface(StrEq(root + "charger/battery_fail.png"), _))
143             .WillRepeatedly(Invoke([](const auto&, GRSurface** surface) {
144                 *surface = nullptr;
145                 return 0;
146             }));
147     EXPECT_CALL(*charger,
148                 CreateMultiDisplaySurface(StrEq(root + "charger/battery_scale.png"), _, _, _))
149             .WillRepeatedly(Invoke([&](const auto&, int* frames, int* fps, GRSurface*** surface) {
150                 *frames = arraysize(multi);
151                 *fps = 60;  // Unused fps value
152                 *surface = multi;
153                 return 0;
154             }));
155     struct healthd_config healthd_config;
156     InitHealthdConfig(&healthd_config);
157     charger->Init(&healthd_config);
158 };
159 
160 // Test that if resources does not exist in /res or in /product/etc/res, load from /system.
TEST(ChargerLoadAnimationRes,Empty)161 TEST(ChargerLoadAnimationRes, Empty) {
162     ForkTest("empty", std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
163 }
164 
165 // Test loading everything from /res
TEST(ChargerLoadAnimationRes,Legacy)166 TEST(ChargerLoadAnimationRes, Legacy) {
167     ForkTest("legacy", std::bind(&ExpectChargerResAt, "/res/images/"));
168 }
169 
170 // Test loading animation text from /res but images from /system if images does not exist under
171 // /res.
TEST(ChargerLoadAnimationRes,LegacyTextSystemImages)172 TEST(ChargerLoadAnimationRes, LegacyTextSystemImages) {
173     ForkTest("legacy_text_system_images",
174              std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
175 }
176 
177 // Test loading everything from /product
TEST(ChargerLoadAnimationRes,Product)178 TEST(ChargerLoadAnimationRes, Product) {
179     ForkTest("product", std::bind(&ExpectChargerResAt, "/product/etc/res/images/"));
180 }
181 
182 }  // namespace android
183