1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstdio>
17 #include <climits>
18 #include <thread>
19
20 #include "gtest/gtest.h"
21 #include "purgeable_memory.h"
22
23 namespace {
24 using namespace testing;
25 using namespace testing::ext;
26
27 struct AlphabetInitParam {
28 char start;
29 char end;
30 };
31
32 struct AlphabetModifyParam {
33 char src;
34 char dst;
35 };
36
37 static constexpr int PRINT_INTERVAL_SECONDS = 1;
38 static constexpr int RECLAIM_INTERVAL_SECONDS = 1;
39 static constexpr int MODIFY_INTERVAL_SECONDS = 2;
40
41 bool InitData(void *data, size_t size, char start, char end);
42 bool ModifyData(void *data, size_t size, char src, char dst);
43 bool InitAlphabet(void *data, size_t size, void *param);
44 bool ModifyAlphabetX2Y(void *data, size_t size, void *param);
45 void LoopPrintAlphabet(OH_PurgeableMemory *pdata, unsigned int loopCount);
46 bool ReclaimPurgeable(void);
47 void LoopReclaimPurgeable(unsigned int loopCount);
48 void ModifyPurgMemByFunc(OH_PurgeableMemory *pdata, OH_PurgeableMemory_ModifyFunc Modfunc, void *param);
49
50 class PurgeableMemoryTest : public testing::Test {
51 public:
52 static void SetUpTestCase();
53 static void TearDownTestCase();
54 void SetUp() override;
55 void TearDown() override;
56 };
57
SetUpTestCase()58 void PurgeableMemoryTest::SetUpTestCase()
59 {
60 }
61
TearDownTestCase()62 void PurgeableMemoryTest::TearDownTestCase()
63 {
64 }
65
SetUp()66 void PurgeableMemoryTest::SetUp()
67 {
68 }
69
TearDown()70 void PurgeableMemoryTest::TearDown()
71 {
72 }
73
74 HWTEST_F(PurgeableMemoryTest, MultiObjCreateTest, TestSize.Level1)
75 {
76 const char alphabetFinal[] = "BBCDEFGHIJKLMNOPQRSTUVWXYZ\0";
77 struct AlphabetInitParam initPara = {'A', 'Z'};
78 OH_PurgeableMemory *pobj1 = OH_PurgeableMemory_Create(27, InitAlphabet, &initPara);
79 LoopPrintAlphabet(pobj1, 1);
80 struct AlphabetModifyParam a2b = {'A', 'B'};
81 ModifyPurgMemByFunc(pobj1, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
82 LoopPrintAlphabet(pobj1, 1);
83 LoopReclaimPurgeable(1);
84
85 if (OH_PurgeableMemory_BeginRead(pobj1)) {
86 ASSERT_STREQ(alphabetFinal, static_cast<char *>(OH_PurgeableMemory_GetContent(pobj1)));
87 OH_PurgeableMemory_EndRead(pobj1);
88 }
89
90 EXPECT_EQ(OH_PurgeableMemory_Destroy(pobj1), true);
91 }
92
93
94 HWTEST_F(PurgeableMemoryTest, WriteTest, TestSize.Level1)
95 {
96 const char alphabet[] = "CCCDEFGHIJKLMNOPQRSTUVWXYZ\0";
97 struct AlphabetInitParam initPara = {'A', 'Z'};
98 OH_PurgeableMemory *pobj = OH_PurgeableMemory_Create(27, InitAlphabet, &initPara);
99 LoopReclaimPurgeable(1);
100
101 struct AlphabetModifyParam a2b = {'A', 'B'};
102 struct AlphabetModifyParam b2c = {'B', 'C'};
103 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&a2b));
104 ModifyPurgMemByFunc(pobj, ModifyAlphabetX2Y, static_cast<void *>(&b2c));
105
106 if (OH_PurgeableMemory_BeginRead(pobj)) {
107 ASSERT_STREQ(alphabet, static_cast<char *>(OH_PurgeableMemory_GetContent(pobj)));
108 OH_PurgeableMemory_EndRead(pobj);
109 } else {
110 std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
111 }
112
113 OH_PurgeableMemory_Destroy(pobj);
114 LoopReclaimPurgeable(3);
115 }
116
InitData(void * data,size_t size,char start,char end)117 bool InitData(void *data, size_t size, char start, char end)
118 {
119 char *str = (char *)data;
120 size_t len = 0;
121 for (char ch = start; ch <= end && len < size; ch++) {
122 str[len++] = ch;
123 }
124 str[len] = 0;
125 return true;
126 }
127
InitAlphabet(void * data,size_t size,void * param)128 bool InitAlphabet(void *data, size_t size, void *param)
129 {
130 struct AlphabetInitParam *para = (struct AlphabetInitParam *)param;
131 std::cout << "inter " << __func__ << std::endl;
132 bool ret = InitData(data, size, para->start, para->end);
133 std::cout << "quit " << __func__ << ": " << para->start << "-" << para->end <<
134 ", data=[" << (char *)data << "]" << ", ret=" << (ret ? "true" : "false") << std::endl;
135 return ret;
136 }
137
ModifyData(void * data,size_t size,char src,char dst)138 bool ModifyData(void *data, size_t size, char src, char dst)
139 {
140 char *str = (char *)data;
141 size_t i = 0;
142 for (; i < size && str[i]; i++) {
143 if (str[i] == src) {
144 str[i] = dst;
145 }
146 }
147 str[i] = 0;
148 return true;
149 }
150
ModifyAlphabetX2Y(void * data,size_t size,void * param)151 bool ModifyAlphabetX2Y(void *data, size_t size, void *param)
152 {
153 struct AlphabetModifyParam *para = (struct AlphabetModifyParam *)param;
154 std::cout << "inter " << __func__ << ": " << para->src << "->" << para->dst <<
155 ", data=[" << (char *)data << "]" << std::endl;
156 bool ret = ModifyData(data, size, para->src, para->dst);
157 std::cout << "quit , data=[" << (char *)data << "]" << __func__ <<
158 ", ret=" << (ret ? "true" : "false") << std::endl;
159 return ret;
160 }
161
LoopPrintAlphabet(OH_PurgeableMemory * pdata,unsigned int loopCount)162 void LoopPrintAlphabet(OH_PurgeableMemory *pdata, unsigned int loopCount)
163 {
164 std::cout << "inter " << __func__ << std::endl;
165 for (unsigned int i = 0; i < loopCount; i++) {
166 if (!OH_PurgeableMemory_BeginRead(pdata)) {
167 std::cout << __func__ << ": " << i << ". ERROR! BeginRead failed." << std::endl;
168 break;
169 }
170 std::cout << __func__ << ": " << i << ". data=[" <<
171 (char *)OH_PurgeableMemory_GetContent(pdata) << "]" << std::endl;
172 OH_PurgeableMemory_EndRead(pdata);
173 std::this_thread::sleep_for(std::chrono::seconds(PRINT_INTERVAL_SECONDS));
174 }
175 std::cout << "quit " << __func__ << std::endl;
176 }
177
ReclaimPurgeable(void)178 bool ReclaimPurgeable(void)
179 {
180 FILE *f = fopen("/proc/sys/kernel/purgeable", "w");
181 if (!f) {
182 std::cout << __func__ << ": open file failed" << std::endl;
183 return false;
184 }
185 bool succ = true;
186 if (fputs("1", f) == EOF) {
187 succ = false;
188 }
189
190 if (fclose(f) == EOF) {
191 std::cout << __func__ << ": close file failed" << std::endl;
192 }
193
194 return succ;
195 }
196
LoopReclaimPurgeable(unsigned int loopCount)197 void LoopReclaimPurgeable(unsigned int loopCount)
198 {
199 bool ret = false;
200 std::cout << "inter " << __func__ << std::endl;
201 for (unsigned int i = 0; i < loopCount; i++) {
202 ret = ReclaimPurgeable();
203 std::cout << __func__ << ": " << i << ". Reclaim result=" << (ret ? "succ" : "fail") << std::endl;
204 std::this_thread::sleep_for(std::chrono::seconds(RECLAIM_INTERVAL_SECONDS)); /* wait reclaim finish */
205 }
206 std::cout << "quit " << __func__ << std::endl;
207 }
208
ModifyPurgMemByFunc(OH_PurgeableMemory * pdata,OH_PurgeableMemory_ModifyFunc Modfunc,void * param)209 void ModifyPurgMemByFunc(OH_PurgeableMemory *pdata, OH_PurgeableMemory_ModifyFunc Modfunc, void *param)
210 {
211 if (OH_PurgeableMemory_BeginWrite(pdata)) {
212 std::this_thread::sleep_for(std::chrono::seconds(MODIFY_INTERVAL_SECONDS));
213 OH_PurgeableMemory_AppendModify(pdata, Modfunc, param);
214 std::cout<< __func__ << " after mod data=[" << (char *)OH_PurgeableMemory_GetContent(pdata) << "]" << std::endl;
215
216 std::cout << __func__ << " data=[" << (char *)OH_PurgeableMemory_GetContent(pdata) << "]" << std::endl;
217 OH_PurgeableMemory_EndWrite(pdata);
218 }
219 }
220 } /* namespace */
221